从另一个线程读取共享变量(Effective Java#66) [英] Reading shared variable from another thread (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 $ c $
所以主线程修改 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屋!