从另一个线程读取共享变量(Effective Java#66)

Hua*_*.Li 7 java concurrency

Effective Java:第66项中,Joshua Bloch举了一个关于生命失败的例子:

// Broken! - How long would you expect this program to run
class StopThread {
    private static boolean stopRequested = false;

    public static void main(String[] args) 
            throws InterruptedException {

        Thread backgroundThread = new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (!stopRequested) {
                    i++;
                }
           }
        });
        backgroundThread.start();

        TimeUnit.SECONDS.sleep(1);
        stopRequested = true;
    }   
}
Run Code Online (Sandbox Code Playgroud)

正如约书亚布洛赫所说,这个计划不会终止.但是,如果我改变i++System.out.println(i++),它成功终止!

我无法弄清楚它是如何发生的!

Dav*_*INO 5

问题与变量的内存值有关stopRequest.

此变量未定义为volatile.

如果您有两个处理器,则内部线程检查stopRequest从其注册表中获取的值.

主线程改变stopRequest了另一个处理器的注册表中的值.

所以主线程修改了一个值stopRequest但线程只看到了一个永远不会改变的副本.

修改后看一下源代码PrintStream(感谢ΔλЛ的推荐):使用一个System.out.print命令将使用一个显式synchronized块来打印传递给它的值,这将授予该值stopRequest来自主内存而不是来自处理器的注册表.

添加volatile关键字将通知JVM从主存储器中获取值,而不是处理器的注册表,它可以解决问题.

同样使用关键字synchronized将解决此问题,因为在synchronized块中使用的任何变量都将被采用并更新主存储器.

没有内存模型volatile(主线程使用处理器1和显式线程使用处理器2)

Processor 1         Processor 2     Main memory
-----------         -----------     -----------
  false                false           false
  true                 false           true       // After setting 
                                                  //stopRequest to true
Run Code Online (Sandbox Code Playgroud)

定义stopRequestvolatile所有线程读取其中stopRequest从主内存.

    Processor 1         Processor 2     Main memory
-----------         -----------     -----------
       NA                   NA           false
       NA                   NA           true       // After setting 
                                                  //stopRequest to true
Run Code Online (Sandbox Code Playgroud)

  • 是的....但我认为Joshua的努力是要解释一个微妙的错误也会产生非常奇怪的错误,但是肯定AtomicBoolean也会解决这个问题. (3认同)
  • 为什么使用`System.out.print`使用另一个线程? (2认同)