CopyOnWriteArrayList 如何是线程安全的? [英] How can CopyOnWriteArrayList be thread-safe?
问题描述
我查看了 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);
另一方面,get(int)
方法只return get(getArray(), index);
.
在我对 JMM 的理解中,这意味着如果语句 1-4 像 1-2(new)-4-2(copyOf)- 那样重新排序,则 get
可能会观察到处于不一致状态的数组3.
我是否对 JMM 理解有误,或者是否还有其他解释为什么 CopyOnWriteArrayList
是线程安全的?
如果您查看底层数组引用,您会看到它被标记为 volatile
.当写操作发生时(例如在上面的摘录中),这个 volatile
引用只在最后的语句中通过 setArray
更新.直到此时,任何读取操作都将从数组的旧副本返回元素.
重要的一点是数组更新是一个原子操作,因此读取将始终看到数组处于一致状态.
只为写操作取出锁的优点是提高了读取的吞吐量:这是因为 CopyOnWriteArrayList
的写操作可能会非常慢,因为它们涉及复制整个列表.>
I've taken a look into OpenJDK source code of CopyOnWriteArrayList
and it seems that all write operations are protected by the same lock and read operations are not protected at all. As I understand, under JMM all accesses to a variable (both read and write) should be protected by lock or reordering effects may occur.
For example, set(int, E)
method contains these lines (under lock):
/* 1 */ int len = elements.length;
/* 2 */ Object[] newElements = Arrays.copyOf(elements, len);
/* 3 */ newElements[index] = element;
/* 4 */ setArray(newElements);
The get(int)
method, on the other hand, only does return get(getArray(), index);
.
In my understanding of JMM, this means that get
may observe the array in an inconsistent state if statements 1-4 are reordered like 1-2(new)-4-2(copyOf)-3.
Do I understand JMM incorrectly or is there any other explanations on why CopyOnWriteArrayList
is thread-safe?
If you look at the underlying array reference you'll see it's marked as volatile
. When a write operation occurs (such as in the above extract) this volatile
reference is only updated in the final statement via setArray
. Up until this point any read operations will return elements from the old copy of the array.
The important point is that the array update is an atomic operation and hence reads will always see the array in a consistent state.
The advantage of only taking out a lock for write operations is improved throughput for reads: This is because write operations for a CopyOnWriteArrayList
can potentially be very slow as they involve copying the entire list.
这篇关于CopyOnWriteArrayList 如何是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!