既不使用volatile也不使用局部变量的java双重检查锁定
在不考虑这一点之前,可以在不使用volatile的情况下执行双重检查锁定,见下文。我建议在这个基础上做一个改变,去掉局部变量
以下是Shipilev的双重检查锁定的正确实现:
public class FinalWrapperFactory {
private FinalWrapper wrapper;
public Singleton get() {
FinalWrapper w = wrapper;
if (w == null) { // check 1
synchronized(this) {
w = wrapper;
if (w == null) { // check2
w = new FinalWrapper(new Singleton());
wrapper = w;
}
}
}
return w.instance;
}
private static class FinalWrapper {
public final Singleton instance;
public FinalWrapper(Singleton instance) {
this.instance = instance;
}
}
}
我想知道是否有可能去掉局部变量^{
public class FinalWrapperFactory {
private FinalWrapper wrapper; //same as example above
public Singleton get() {
if (wrapper == null) { // read 1
synchronized(this) {
if (wrapper == null) { // read 2
wrapper = new FinalWrapper(new Singleton());
return wrapper.instance; // read 3
} else {
return wrapper.instance; // read 4
}
}
} else {
return wrapper.instance; // read 5 (last read). Can this be reordered?
}
}
}
在JLS 8的17.4.8. Executions and Causality Requirements中写着:
Informally, we allow an action to be committed early if we know that the action can occur without assuming some data race occurs.
这里的一个大问题是,最后一次读取(读取5)是否可以重新排序,这样我们就可以在读取1中看到一个非空的包装,而在最后一次读取中仍然可以看到一个空的包装。在线程第一次调用get()
时,不应允许发生这种情况,因为最后一次读取的唯一方式是数据竞争,JMM将禁止重新排序
在get()
的后续调用中,可以进行重新排序,但这并不重要,因为包装器无论如何都应该是可见的
共 (0) 个答案