java - 与 System.out 关联的 Java 线程的奇怪行为

标签 java multithreading race-condition

<分区>

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

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

操作系统:Windows 8.1 标志完成设置为真 ...

第二个线程永远存在。因为第二个线程永远不会看到由主线程设置为 true 的 done 标志的变化。

  1. 当我取消注释 System.out.println(count); 时,输出是:

    操作系统:Windows 8.1 0 ... 190785 190786 标志完成设置为真 完毕! 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 ");
    }
}

最佳答案

这是 memory consistency errors 的一个绝妙例子.简而言之,变量已更新,但第一个线程并不总是看到变量更改。这个问题可以通过声明 done 变量 volatile 来解决:

private static volatile boolean done;

在这种情况下,对变量的更改对所有线程都是可见的,并且程序总是在一秒后终止。

更新:似乎使用 System.out.println 确实解决了内存一致性问题 - 这是因为打印功能使用了底层流,它实现同步。同步建立了一个 happens-before 关系,如我链接的教程中所述,它与 volatile 变量具有相同的效果。 (来自 this answer 的详细信息。也感谢@Chris K 指出了流操作的副作用。)

关于java - 与 System.out 关联的 Java 线程的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32294288/

相关文章:

java - try catch 循环问题

java - 如何从 Android kotlin 中的非 Activity 类开始新 Activity ?

java - 在JAVA中添加分数时如何避免舍入错误

ruby-on-rails - 如何在Rails 4.0中填充activerecord时加载动画?

java - 单个QueueConnection可以在多线程环境中使用吗?

c++ - 使用 FIONREAD 调用 ioctl() 会在明显的竞争条件下产生奇怪的副作用,

java - 处理映射总是越界

multithreading - 使用 GO 时如何测量系统过载

javascript - 如果一个函数更新状态而另一个函数紧接着访问该状态,是否会导致竞争条件?

python - 复制文件时使用 try/except 或 if/else