【问题标题】:Visibility of mutable instance objects可变实例对象的可见性
【发布时间】:2021-02-27 06:06:37
【问题描述】:

根据“Java 并发实践”一书,以下代码可能会永远执行,或者当 ready 为 true 时 number 的值可能仍为 0,建议将变量定义为 volatile。然而,即使在我多次尝试之后,下面列出的程序似乎总是返回正确的值 (42) 而不是陈旧的值。这是一种很少发生的现象吗?

public class NoVisibility {
    private static boolean ready;
    private static int number;

    private static class ReaderThread extends Thread{
        public void run(){
            System.out.println("Thread started =" + ready + " " + number);
            while(!ready){
                Thread.yield();
            }
            System.out.println("value is" + number);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new ReaderThread().start();
        Thread.sleep(10000);
        number = 42;
        ready = true;
    }
}

【问题讨论】:

  • 你得到的输出是什么,你期望的输出是什么?
  • 我希望循环不会结束或显示 0。但我得到 42 作为输出。
  • 好吧,当您在 ReaderThread 中调用 Thread.yield() 时,它允许主线程首先运行。主线程等待 10000 英里,然后更改这两个变量。并且还终止子线程。我看不出这里有什么意外
  • 我尝试使用循环和多线程,也无法让它搞砸。我想这需要被解释为“不要使用类字段进行进程间通信”,并举例说明要避免什么样的事情,即使在这个简单的情况下以及使用更新的 JVM 所提供的代码也可以正常工作。
  • @Dennishofken 根据本书,您不能确定 ReaderThread 是否会“看到”实例变量的更新值,从而导致无限循环。即使它看到更新的值,也可能在将 number 设置为 42 之前将 ready 设置为 true 的情况。因此,这可能导致 value 被打印为 0。通过同步或设置实例来做到这一点的安全方法在此特定示例中,字段为 volatile。

标签: java multithreading concurrency java.util.concurrent


【解决方案1】:

这是一种很少发生的现象吗

是的,很少见。然而,鉴于计算机每秒执行数十亿次操作,很少见是相当普遍的

每当跨线程访问资源时,您必须地址thread-safety。否则,您在部署中的应用程序将遇到零星的错误,即使不是不可能解决也非常困难。

按照同样的逻辑,众所周知,测试并发错误非常困难,正如您在问题中看到的那样。

尽可能避免使用线程代码。例如,使用immutable objectsdefensive copies

必读:Java Concurrency in Practice Brian Goetz 等人。

【讨论】:

  • Re:“必读:Java Concurrency in Practice by Brian Goetz 等人。”:由于问题的前六个单词是“根据 Java 并发实践” ,我认为可以公平地说不需要该评论。
  • @ruakh 第一句话并不清楚是否是对一本书的参考。而且 Stack Overflow 不是电子邮件——我为成千上万的其他读者写答案,而不是为提出问题的人。
【解决方案2】:

作者说服务器 JVM 比客户端 JVM 执行更多优化。

【讨论】:

    猜你喜欢
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 2011-10-12
    • 2016-12-23
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多