当前位置: 首页 > 面试题库 >

CopyOnWriteArrayList如何是线程安全的?

邵文乐
2023-03-14
问题内容

我看过OpenJDK的OpenJDK源代码,CopyOnWriteArrayList似乎所有写操作都受同一锁保护,而读操作则根本不受保护。据我了解,在JMM下,对变量的所有访问(读和写)都应受锁保护,否则可能会发生重新排序的效果。

例如,set(int, E)method包含以下几行(处于锁定状态):

/* 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的理解中,这意味着get如果将语句1-4重新排序为1-2(new)-4-2(copyOf)-3 ,则可能会在不一致状态下观察到数组。

我是否对JMM理解不正确,或者是否还有其他关于为什么CopyOnWriteArrayList线程安全的解释?


问题答案:

如果您查看基础数组引用,您会看到它被标记为volatile。当发生写操作时(例如,在上面的摘录中),该volatile引用仅在final语句中通过进行更新setArray。到目前为止,所有读取操作都将返回数组
旧副本 中的元素。

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

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



 类似资料:
  • 本文向大家介绍如何理解Java中的StringBuffer是线程安全的而StringBuilder是非线程安全的?,包括了如何理解Java中的StringBuffer是线程安全的而StringBuilder是非线程安全的?的使用技巧和注意事项,需要的朋友参考一下 StringBuffer(线程安全) StringBuffer是线程安全的,这意味着它们具有同步方法来控制访问,因此一次只有一个线程可以

  • 我看到了不同的PHP二进制文件,比如非线程或线程安全? 这是什么意思? 这些软件包之间有什么区别?

  • 本文向大家介绍如何保证线程安全?相关面试题,主要包含被问及如何保证线程安全?时的应答技巧和注意事项,需要的朋友参考一下 考察点:线程 通过合理的时间调度,避开共享资源的存取冲突。另外,在并行任务设计上可以通过适当的策略,保证任务与任务之间不存在共享资源,设计一个规则来保证一个客户的计算工作和数据访问只会被一个线程或一台工作机完成,而不是把一个客户的计算工作分配给多个线程去完成。

  • 本文向大家介绍java枚举是如何保证线程安全的,包括了java枚举是如何保证线程安全的的使用技巧和注意事项,需要的朋友参考一下 前言 写在前面:Java SE5提供了一种新的类型-Java的枚举类型,关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能。本文将深入分析枚举的源码,看一看枚举是怎么实现的,他是如何保证线程安全的

  • 问题内容: 在中,此变量被声明为是我的问题,在某些调用之后检查值还是在多线程代码中使用perror()是安全的。这是线程安全变量吗?如果没有,那还有什么选择呢? 我在x86体系结构上将Linux与gcc一起使用。 问题答案: 是的,它是线程安全的。在Linux上,全局errno变量是特定于线程的。POSIX要求errno必须是线程安全的。 参见http://www.unix.org/whitepa

  • 问题内容: 我们在项目中使用了Drools kieSessions。许多线程可以创建新的kieSession。有时在创建会话时线程可能会挂起。因此,问题是: 首先 是kieContainer.newKieSession线程安全操作吗? 上吊的原因可能是肮脏的文字或阅读的kie会话集之类的东西吗? 问题答案: 当我在实践中检查 不是线程安全的操作。