繁体   English   中英

为什么在执行双重检查锁定时将volatile字段复制到局部变量

[英]Why is the volatile field copied to a local variable when doing double check locking

我正在阅读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;  
}    

它表示使用result似乎不需要,但实际上确保该field仅在已经初始化的常见情况下只读取一次。

但我不明白这一点。 直接执行if(field == null)有什么区别? 我不明白为什么if (result == null)不同,更不用说如上所述了。

解释在下一页(我强调):

这个变量的作用是确保该字段在已经初始化的常见情况下只读一次。 虽然不是绝对必要, 但这可以提高性能,并且通过应用于低级并发编程的标准更加优雅。 在我的机器上,上面的方法比没有局部变量的明显版本快25%。

作为参考,报价来自p。 项71的284:在Effective Java 2nd Edition中明智地使用延迟初始化

更新 :读取本地变量和volatile变量之间的区别在于前者可以更好地进行优化。 易失性变量不能存储在寄存器或高速缓存中,也不能对它们的存储器操作进行重新排序。 此外,读取volatile变量可能会触发不同线程之间的内存同步。

有关更多详细信息,请参阅实践中的Java并发 ,第3.1.4节: 易失性变量

在这个例子中的想法是结果/字段将被进一步使用,我想。 访问result更便宜(它不易变)。

否则,在返回时会有第二个易失性读取。

如果需要,请使用initializaton on demand holder模式。 http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom

在评论中添加我对答案本身的一些澄清以便......清晰度:

短版本:一个局部变量可以只在一个(一个)cpu(和一个cpu的核心,如果多个等)的寄存器中。 这和它一样快。 必须检查volatile变量是否有其他core / caches / cpus / memory的更改,但细节可能非常特定于硬件(缓存行,内存屏障等)。 但也特定于jvm(例如,热点服务器编译器可能会提升非易失性变量)并且它对重新排序指令施加限制以获得可能的性能增益

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM