Fix*_*int 56 java concurrency java-memory-model data-structures
我已经看了一下OpenJDK的源代码,CopyOnWriteArrayList似乎所有的写操作都受到同一个锁的保护,读操作根本就没有受到保护.据我所知,在JMM下,所有对变量(读取和写入)的访问都应该受到锁定或重新排序的影响.
例如,set(int, E)方法包含这些行(在锁定下):
/* 1 */ int len = elements.length;
/* 2 */ Object[] newElements = Arrays.copyOf(elements, len);
/* 3 */ newElements[index] = element;
/* 4 */ setArray(newElements);
Run Code Online (Sandbox Code Playgroud)
get(int)另一方面,该方法仅适用return get(getArray(), index);.
在我对JMM的理解中,这意味着get如果语句1-4被重新排序,如1-2(新)-4-2(copyOf)-3 ,则可能会观察到数组处于不一致状态.
我是否理解JMM不正确或是否有任何其他解释为什么CopyOnWriteArrayList线程安全?
Ada*_*ski 70
如果查看底层数组引用,您会看到它被标记为volatile.当发生写操作时(例如在上面的提取中),该volatile引用仅在最终语句中更新setArray.到目前为止,任何读取操作都将从数组的旧副本返回元素.
重要的一点是,数组更新是一个原子操作,因此读取将始终看到数组处于一致状态.
仅对写入操作取出锁定的优点是提高了读取的吞吐量:这是因为对于a的写入操作CopyOnWriteArrayList可能非常慢,因为它们涉及复制整个列表.
mdm*_*dma 19
获取数组引用是一种原子操作.因此,读者将看到旧数组或新数组 - 无论哪种状态都是一致的.(set(int,E)在设置引用之前计算新的数组内容,因此在进行asignment时数组是一致的.)
数组引用本身被标记为volatile使得读者不需要使用锁来查看引用数组的更改.(编辑:另外,volatile保证不重新排序赋值,这将导致在数组可能处于不一致状态时完成赋值.)
需要写锁来防止并发修改,这可能导致数组保持不一致的数据或更改丢失.
| 归档时间: |
|
| 查看次数: |
15660 次 |
| 最近记录: |