采取以下java代码:
public class SomeClass {
private boolean initialized = false;
private final List<String> someList;
public SomeClass() {
someList = new ConcurrentLinkedQueue<String>();
}
public void doSomeProcessing() {
// do some stuff...
// check if the list has been initialized
if (!initialized) {
synchronized(this) {
if (!initialized) {
// invoke a webservice that takes a lot of time
final List<String> wsResult = invokeWebService();
someList.addAll(wsResult);
initialized = true;
}
}
}
// list is initialized
for (final String s : someList) {
// do more stuff...
}
}
}
诀窍是doSomeProcessing
仅在某些条件下才被调用。初始化列表是一个非常昂贵的过程,可能根本不需要它。
我已经阅读了关于为什么双重检查习语被破坏的文章,当我看到这段代码时我有点怀疑。然而,这个例子中的控制变量是一个布尔值,所以据我所知,需要一个简单的写指令。
另外,请注意someList
已被声明为final
并保留对并发列表的引用,该列表的writes
发生之前 reads
;如果不是一个ConcurrentLinkedQueue
列表是一个简单的ArrayList
or LinkedList
,即使它已被声明为final
,writes
也不需要在 .之前发生reads
。
那么,上面给出的代码是否没有数据竞争?