我已经研究过OpenJDK 源代码 http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/4797cd0713b4/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java of CopyOnWriteArrayList http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CopyOnWriteArrayList.html似乎所有写操作都受到同一个锁的保护,而读操作则根本不受保护。据我了解,在 JMM 下,对变量的所有访问(读和写)都应该受到锁的保护,否则可能会发生重新排序效应。
例如,set(int, E)
方法包含这些行(处于锁定状态):
/* 1 */ int len = elements.length;
/* 2 */ Object[] newElements = Arrays.copyOf(elements, len);
/* 3 */ newElements[index] = element;
/* 4 */ setArray(newElements);
The get(int)
另一方面,方法只return get(getArray(), index);
.
根据我对 JMM 的理解,这意味着get
如果语句 1-4 像 1-2(new)-4-2(copyOf)-3 那样重新排序,则可能会观察到数组处于不一致状态。
我对 JMM 的理解是否错误,或者是否有其他解释CopyOnWriteArrayList
是线程安全的吗?
如果您查看底层数组引用,您会看到它被标记为volatile
。当发生写操作时(例如上面的摘录)volatile
参考仅在最终声明中更新setArray
。到目前为止,任何读取操作都将从old copy数组的。
重要的一点是数组更新是一个原子操作因此读取时总是会看到数组处于一致状态。
只为写操作取出锁的优点是提高了读的吞吐量:这是因为写操作CopyOnWriteArrayList
可能会非常慢,因为它们涉及复制整个列表。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)