与System.out关联的Java线程的奇怪行为 [英] Strange behavior of a Java thread associated with System.out
问题描述
我有一个简单的TestThreadClientMode
类来测试竞争条件.我尝试了两次:
- 当我在第二个线程中用
System.out.println(count);
注释运行以下代码时,输出为:
OS: Windows 8.1
flag done set true
...
,第二个线程永远存在.因为第二个线程永远看不到主线程将其设置为true的done
标志更改.
-
当我取消注释
System.out.println(count);
时,输出为:OS: Windows 8.1 0 ... 190785 190786 flag done set true Done! Thread-0 true
程序在1秒后停止.
System.out.println(count);
如何使第二个线程看到done
中的更改?
代码
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 ");
}
}
这是内存一致性错误.简而言之,变量已更新,但是第一个线程并不总是看到变量的变化.可以通过这样声明done
变量volatile
来解决此问题:
private static volatile boolean done;
在这种情况下,对变量的更改对所有线程可见,并且程序始终一秒钟后终止.
更新:看来使用System.out.println
确实可以解决内存一致性问题-这是因为打印功能利用了实现同步的基础流.同步建立了我所链接的教程中所述的事前发生关系,该关系与volatile变量具有相同的作用. (来自此答案的详细信息.还要感谢@Chris K指出流操作的副作用.)>
I have a simple TestThreadClientMode
class to test a race condition. I tried two attempts:
- When I run the following code with
System.out.println(count);
commented in the second thread, the output was:
OS: Windows 8.1
flag done set true
...
and the second thread was alive forever. Because the second thread never sees change of the done
flag which was set true by Main thread.
When I uncommented
System.out.println(count);
the output was:OS: Windows 8.1 0 ... 190785 190786 flag done set true Done! Thread-0 true
And the program stopped after 1 second.
How did System.out.println(count);
make the second thread see the change in done
?
Code
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 ");
}
}
This is a brilliant example of memory consistency errors. Simply put, the variable is updated but the first thread does not always see the variable change. This issue can be solved by making done
variable volatile
by declaring it like so:
private static volatile boolean done;
In this case, changes to the variable are visible to all threads and the program always terminates after one second.
Update: It appears that using System.out.println
does indeed solve the memory consistency issue - this is because the print function makes use of an underlying stream, which implements synchronization. Synchronization establishes a happens-before relationship as described in the tutorial I linked, which has the same effect as the volatile variable. (Details from this answer. Also credit to @Chris K for pointing out the side effect of the stream operation.)
这篇关于与System.out关联的Java线程的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!