与System.out关联的Java线程的奇怪行为 [英] Strange behavior of a Java thread associated with System.out

查看:86
本文介绍了与System.out关联的Java线程的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的TestThreadClientMode类来测试竞争条件.我尝试了两次:

  1. 当我在第二个线程中用System.out.println(count);注释运行以下代码时,输​​出为:

OS: Windows 8.1 flag done set true ...

,第二个线程永远存在.因为第二个线程永远看不到主线程将其设置为true的done标志更改.

  1. 当我取消注释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:

  1. 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.

  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆