java – 使用布尔值双重检查成语
采取以下
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,并保留对并发列表的引用,其写入发生在读取之前;如果不是ConcurrentLinkedQueue,则列表是一个简单的ArrayList或LinkedList,即使它已被声明为final,也不需要在读取之前进行写入. 那么,上面给出的代码是否没有数据竞争? 解决方法
好的,让我们来获取Java语言规范.第17.4.5节
defines happens-before如下:
然后继续讨论两个:
在您的实例中,线程检查 if (!initialized) 可以在看到添加到someList的所有写入之前看到初始化的新值,因此可以使用部分填充的列表. 请注意你的论点
是无关紧要的.是的,如果线程从列表中读取一个值,我们可以得出结论,他也会在写入该值之前看到发生的任何事情.但如果它没有读取值呢?如果列表显示为空,该怎么办?即使它读取了值,也不意味着后续写入已经执行,因此列表可能看起来不完整. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |