从另一个线程读取共享变量(Effective Java#66) [英] Reading shared variable from another thread (Effective Java #66)

查看:141
本文介绍了从另一个线程读取共享变量(Effective Java#66)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  //破碎! - 你期望这个程序运行多长时间
class StopThread {
private static boolean stopRequested = false;

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

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

TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}

正如Joshua Bloch所说,这个程序不会终止。
但是,如果我将 i ++ 更改为 System.out.println(i ++),它会成功终止!



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

解决方案

该问题与变量 stopRequest 的内存值相关。



此变量未定义为 volatile



如果你有两个处理器,内线程检查 stopRequest 取自其注册表。



主线程更改 stopRequest

所以主线程修改 stopRequest 的值,但线程



修改后查看 PrintStream的源代码(感谢Δλthe的推荐):使用 System.out.print 命令将使用显式 synchronized block打印传递给它的值,这将允许 stopRequest 的值取自主内存,而不是从处理器的注册表。 p>

添加一个 volatile 关键字将通知JVM从主内存中获取值,而不是从处理器的注册表中获取值;它解决了问题。



同样使用关键字同步会解决这个问题,因为在同步块中使用的任何变量都被采用,主线程使用处理器1和显式线程使用处理器2)



内存模型不含 volatile p>

 处理器1处理器2主内存
----------- ------- ---- -----------
false false false
true false true //设置
// stopRequest为true

定义 stopRequest volatile 其中所有线程从主存储器读取 stopRequest

 处理器1处理器2主存
----------- ----------- -----------
NA NA false
NA NA true //设置
// stopRequest为true


In Effective Java: item 66, Joshua Bloch gave an example about life failure:

// 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;
    }   
}

As Joshua Bloch said, this program would not terminate. But, if I change i++ into System.out.println(i++), it terminates successfully!

I can't figure out how it happens!

解决方案

The problem is related to the memory value of the variable stopRequest.

This variable is not defined as volatile.

If you have a two processors the inner thread check the value of stopRequest taken from its registry.

The main thread alter the value of stopRequest in the registry of the other processor.

So the main thread modify a value of stopRequest but the thread see only a copy of it that never changes.

Modified after take a look at the source code of PrintStream (thanks to the commend of ΔλЛ): Using a System.out.print command will use an explicit synchronized block to print the value passed to it this will grant that the value of stopRequest is taken from the main memory and not from the registry of the processor.

Adding a volatile keyword will inform the JVM to take the value from the main memory instead from the registries of the processors and it solve the problem.

Also using the keyword synchronized will solve this problem because any variable used in the synchronized block is taken and update the main memory.

Memory model without volatile (Main thread use Processor 1 and explicit thread use Processor 2)

Processor 1         Processor 2     Main memory
-----------         -----------     -----------
  false                false           false
  true                 false           true       // After setting 
                                                  //stopRequest to true

Defining stopRequest as volatile where all threads read stopRequest from main memory.

    Processor 1         Processor 2     Main memory
-----------         -----------     -----------
       NA                   NA           false
       NA                   NA           true       // After setting 
                                                  //stopRequest to true

这篇关于从另一个线程读取共享变量(Effective Java#66)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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