我有一个简单的TestThreadClientMode
类来测试竞争条件。我尝试了两次:
System.out运行以下代码时。println(计数)
在第二个线程中注释,输出为:操作系统:Windows 8.1标志完成设置为真…
第二个线程永远活着。因为第二个线程永远看不到主线程设置为true的完成
标志的变化。
当我取消注释< code>System.out.println(count)时;输出是:
OS:Windows 8.1 0…190785 190786标志完成设置为true完成!线程-0为真
程序在1秒后停止。
系统.out.println(计数);
如何使第二个线程看到所做的更改完成
?
public class TestThreadClientMode {
private static boolean done;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
int count = 0;
while (!done) {
count ++;
//System.out.println(count);
}
System.out.println("Done! " + Thread.currentThread().getName() + " " + done);
}
}).start();
System.out.println("OS: " + System.getProperty("os.name"));
Thread.sleep(1000);
done = true;
System.out.println("flag done set true ");
}
}
println()
实现包含显式内存屏障:
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
这导致调用线程刷新所有变量。
以下代码将具有与您的代码相同的行为:
public void run() {
int count = 0;
while (!done) {
count++;
synchronized (this) {
}
}
System.out.println("Done! " + Thread.currentThread().getName() + " " + done);
}
事实上,任何对象都可以用于监视器,以下内容也适用:
synchronized ("".intern()) {
}
创建显式内存屏障的另一种方法是使用易失性
,因此以下方法将起作用:
new Thread() {
private volatile int explicitMemoryBarrier;
public void run() {
int count = 0;
while (!done) {
count++;
explicitMemoryBarrier = 0;
}
System.out.println("Done! " + Thread.currentThread().getName() + " " + done);
}
}.start();
System.out.println(count)是怎么做到的;让第二个线程看到< code>done中的变化?
您正在见证打印的副作用;您的程序正在遭受并发争用情况的困扰。在 CPU 之间协调数据时,告诉 Java 程序您希望在 CPU 之间共享数据非常重要,否则 CPU 可以自由地延迟彼此之间的通信。
有几种方法可以在 Java 中执行此操作。主要的两个是关键字“易失性”和“同步”,它们都将硬件人员称为“内存障碍”的东西插入到代码中。如果不在代码中插入“内存屏障”,则不会定义并发程序的行为。也就是说,我们不知道“完成”何时对其他CPU可见,因此它是一个竞争条件。
这是系统输出的实现;注意使用同步。synchroniz 关键字负责在生成的汇编程序中放置内存屏障,这会产生使变量“完成”对其他 CPU 可见的副作用。
public void println(boolean x) {
synchronized (this) {
print(x);
newLine();
}
}
正确的程序修复方法是,在读取完成时放置一个读内存屏障,在写入时放置写内存屏障。通常,这是通过从同步块中读取或写入“done”来完成的。在这种情况下,将变量done
标记为volatile
将产生相同的净效果。您还可以对变量使用AtomicBoolean
而不是boolean
。
这是内存一致性错误的一个很好的例子。简单地说,变量被更新了,但第一个线程并不总是看到变量发生了变化。这个问题可以通过如下声明使完成
变量易失性
来解决:
private static volatile boolean done;
在这种情况下,对变量的更改对所有线程都可见,程序总是在一秒钟后终止。
更新:似乎使用System.out。println
确实解决了内存一致性问题,这是因为print函数使用了实现同步的底层流。同步建立了我链接的教程中描述的“先发生后发生”关系,其效果与volatile变量相同。(此答案的详细信息。还感谢@Chris K指出了流操作的副作用。)
好的,最近我在寻找一种在PowerShell中实现空合并的方法,我遇到了这篇文章:在PowerShells中实现空聚合。 我看到了@Zenexer的评论,很感兴趣。语法如下: 这非常有效。然而,我的一位同事(沃尔特·帕克特)和我非常感兴趣,对语法做了更多的挖掘,发现了一些真正的奇怪之处。 在我进入怪异之前,任何人都可以指出任何解释这种语法的文档吗? 经验教训: < li >测试应该进入数组的最后一
所以我更新了代码,添加了行所做的是将主线程置于Hibernate状态一段时间,因此jvm可以获得一些时间来创建一个新线程。我正在得到我的预期输出
我有一个ui显示的数据表:repeat。因为我希望用户能够在每行的基础上更改数据,所以每行都包含在一个h:form中。最后,每个h:form都有一个带有f:ajax标记的按钮。我的行为越来越不一致。 上述方法可行,但带宽显然不便宜。 如果我将render=“@all”更改为render=“@form”,Firebug显示发送的部分响应正常,但我的浏览器(Firefox)神秘地没有显示它。所以我猜它
问题内容: 我有以下简单代码: 正如我的python知识所期望的那样,输出为3-整个列表将包含的最后一个值。但是,这在内部如何运作? AFAIK,python变量只是对对象的引用,因此第一个闭包必须包含对象的第一个引用-并且此对象肯定是1,而不是3 O_O。python闭包如何将变量本身而不是对象作为变量引用的对象?它是否将变量名另存为纯文本,一些“对变量的引用”或什么? 问题答案: 闭包不是指
我发现了Java并发的奇怪行为。请参阅下面的下一段代码: 在我看来,这段代码应该挂起并永远等待,但是在控制台中的next out没有任何问题地完成了代码: 我试图找到一些关于如果线程死了通知锁的信息,但缺乏。我也没有在Java规范中找到任何信息。 但是如果我试图锁定其他对象(而不是thread对象),就会像我预期的那样工作得很好。
如果有人理解java编译器为什么这么做,请解释一下。