首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CopyOnWriteArrayList怎么可能是线程安全的?

CopyOnWriteArrayList怎么可能是线程安全的?
EN

Stack Overflow用户
提问于 2010-06-01 23:01:17
回答 4查看 17.7K关注 0票数 59

我研究了CopyOnWriteArrayListOpenJDK source code,似乎所有写操作都受到相同锁的保护,而读操作根本不受保护。据我所知,在JMM下,对变量的所有访问(包括读和写)都应该受到锁的保护,否则可能会出现重新排序的效果。

例如,set(int, E)方法包含以下行(在锁定状态下):

代码语言:javascript
复制
/* 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是线程安全的,还有其他解释吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2010-06-01 23:05:34

如果你看一下底层的数组引用,你会发现它被标记为volatile。当发生写操作时(比如在上面的摘录中),这个volatile引用只在最后一条语句中通过setArray更新。在此之前,任何读操作都将返回数组的旧拷贝中的元素。

重要的一点是,数组更新是一个原子操作,因此读取将始终看到处于一致状态的数组。

只为写操作取出锁的优点是提高了读操作的吞吐量:这是因为CopyOnWriteArrayList的写操作可能非常慢,因为它们涉及复制整个列表。

票数 73
EN

Stack Overflow用户

发布于 2010-06-01 23:05:14

获取数组引用是一个原子操作。因此,读者将看到旧数组或新数组--无论哪种方式,状态都是一致的。(set(int,E)在设置引用之前计算新的数组内容,因此在进行指定时数组是一致的。)

数组引用本身被标记为volatile,这样读取器就不需要使用锁来查看对被引用数组的更改。(编辑:此外,volatile还保证赋值不会重新排序,这将导致在数组可能处于不一致状态时执行赋值。)

需要使用写锁定来防止并发修改,这可能会导致保存不一致数据或更改的阵列丢失。

票数 19
EN

Stack Overflow用户

发布于 2019-10-30 17:53:14

因此,根据Java1.8,下面是CopyOnWriteArrayList.中数组的声明

代码语言:javascript
复制
/** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;

/** The lock protecting all mutators */
    final transient ReentrantLock lock = new ReentrantLock();

下面是CopyOnWriteArrayListadd方法的定义

代码语言:javascript
复制
 public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

正如@Adamski已经提到的,数组是易失性的,并且只能通过setArray方法进行更新。在那之后,如果所有的只读调用都被执行了,那么它们将获得更新值,因此数组在这里总是一致的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2950871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档