Jim*_*Jim 5 java concurrency multithreading synchronization effective-java
我正在阅读关于双重检查锁定的信息Effective Java
.代码执行以下操作:
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
它说使用result
似乎不需要但实际上确保field
只在已经初始化的常见情况下只读取一次.
但我不明白这一点.与if(field == null)
直接做什么有什么区别?我不明白为什么if (result == null)
会有所不同,更不用说如上所述了.
解释在下一页(我强调):
这个变量的作用是确保该字段在已经初始化的常见情况下只读一次.虽然不是绝对必要,但这可以提高性能,并且通过应用于低级并发编程的标准更加优雅.在我的机器上,上面的方法比没有局部变量的明显版本快25%.
作为参考,报价来自p.项71的284:在Effective Java 2nd Edition中明智地使用延迟初始化.
更新:读取本地变量和volatile变量之间的区别在于前者可以更好地进行优化.易失性变量不能存储在寄存器或高速缓存中,也不能对它们的存储器操作进行重新排序.此外,读取volatile变量可能会触发不同线程之间的内存同步.
有关更多详细信息,请参阅实践中的Java并发,第3.1.4节:易失性变量.
我猜想,该示例中的想法是结果/字段将在下面多次使用。访问result
更便宜(它不是易失性的)。
否则,在执行返回时,您将进行第二次易失性读取。
如果您需要这样做,请使用按需初始化持有者模式。 http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
在评论中添加我的一些澄清到答案本身,以便......清晰:
简短版本:局部变量只能位于 cpu(其中之一)的寄存器中(如果有多个,则位于其中一个 cpu 核心)。这已经是最快的了。必须检查易失性变量是否存在其他内核/缓存/CPU/内存中的更改,但详细信息可能非常特定于硬件(缓存行、内存屏障等)。而且还针对 jvm(例如,热点服务器编译器可能会提升非易失性变量),并且它还对重新排序指令施加了限制,以实现可能的性能提升
归档时间: |
|
查看次数: |
410 次 |
最近记录: |