我研究了OpenJDK source code的 CopyOnWriteArrayList
,似乎所有写操作均受同一锁保护,而读操作则根本不 protected 。据我了解,在JMM下,对变量的所有访问(读和写)都应受锁保护,否则可能会发生重新排序的效果。
例如,set(int, E)
方法包含以下几行(处于锁定状态):
/* 1 */ int len = elements.length;
/* 2 */ Object[] newElements = Arrays.copyOf(elements, len);
/* 3 */ newElements[index] = element;
/* 4 */ setArray(newElements);
另一方面,
get(int)
方法仅执行return get(getArray(), index);
。在我对JMM的理解中,这意味着如果将语句1-4重新排序为1-2(new)-4-2(copyOf)-3,则
get
可能会以不一致的状态观察数组。我是否对JMM理解不正确,或者是否对
CopyOnWriteArrayList
为什么是线程安全的有其他解释? 最佳答案
如果您查看基础数组引用,您会看到它被标记为volatile
。当发生写操作时(例如,在上面的摘录中),此volatile
引用仅在最终语句中通过setArray
更新。到目前为止,任何读取操作都将返回数组的旧副本中的元素。
重要的一点是数组更新是一个原子操作,因此读取将始终看到该数组处于一致状态。
只对写操作进行锁定的优点是提高了读取的吞吐量:这是因为CopyOnWriteArrayList
的写操作可能很慢,因为它们涉及复制整个列表。
关于java - CopyOnWriteArrayList如何成为线程安全的?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2950871/