这是Java double checked locking的后续内容。
以下代码段有两个有趣的特征。
1)在对象准备好使用之前,需要调用单独的init()方法。所以volatile不起作用(我知道,为什么我不把init()中的代码放到构造函数中?这是为了说明的目的)。
2)它使用tmp变量进行初始化,并在初始化完成后分配给实例。
if (instance == null) {
synchronized (mutex) {
if (instance == null) {
AClass tmpInstance = new AClass();
tmpInstance.init();
instance = tmpInstance;
}
}
}
那么,这是否受到重新排序问题的影响,即可以在调用tmpInstance.init()之前将实例分配给tmpInstance?
谢谢, 富
答案 0 :(得分:2)
重要的是,在完成所有初始化之后,您将instance
指定为最后一个操作。由于instance
(希望)是易变的,这将确保所有初始化对后来的读者都可见。
顺便说一句,你真的没有必要学习允许重新排序的所有规则:这只是JIT编译器实现者的强制读取。
作为Java程序员,您需要牢记的是Java内存模型为您提供的两个简单保证(一个约为synchronized
,另一个约为volatile
)。 JMM重写的全部内容(从JLS 3开始)是允许我们针对一个非常简单的并发模型进行编程。
答案 1 :(得分:1)
那么,这是否受到重新排序问题的影响,即可能是 在调用tmpInstance.init()之前分配给tmpInstance?
否,但它受到volatile确实解决的可见性问题的影响。所以你仍然应该声明instance
volatile。
现在它不受重新排序的原因。监视器进入后,正常存储无法重新排序。
http://g.oswego.edu/dl/jmm/cookbook.html
第一次操作:MonitorEnter
第二次操作:NormalStore
可以重新排序:否