CopyOnWriteArrayList 如何是线程安全的? [英] How can CopyOnWriteArrayList be thread-safe?

查看:14
本文介绍了CopyOnWriteArrayList 如何是线程安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我查看了 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆