我研究了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/

10-10 17:33