【发布时间】:2013-07-25 08:42:55
【问题描述】:
我正在学习CopyOnWriteArrayList 课程。
- 复制新数组的目的是什么?
- 是让其他线程读取数组吗?
所以如果系统并发高,大部分线程的动作都是读不写,最好使用CopyOnWriteArrayList。
【问题讨论】:
标签: java collections
我正在学习CopyOnWriteArrayList 课程。
所以如果系统并发高,大部分线程的动作都是读不写,最好使用CopyOnWriteArrayList。
【问题讨论】:
标签: java collections
正如link 所述:
CopyOnWriteArrayList 是 Java 5 并发 API 中引入的并发 Collection 类,以及它在 Java 中流行的表亲 ConcurrentHashMap。
CopyOnWriteArrayList 实现了 List 接口,如 ArrayList、Vector 和 LinkedList,但它是一个线程安全的集合,它以与 Vector 或其他线程安全集合类略有不同的方式实现其线程安全。
顾名思义,CopyOnWriteArrayList 创建底层副本 ArrayList 与每个突变操作,例如添加或设置。一般 CopyOnWriteArrayList 非常昂贵,因为它涉及成本高昂 每次写入操作时都进行数组复制,但 如果您这样做会非常有效 有一个迭代超过突变的列表,例如你主要需要 迭代 ArrayList,不要经常修改。
CopyOnWriteArrayList 的迭代器是故障安全的,不会抛出异常 ConcurrentModificationException 即使底层 一旦迭代开始,CopyOnWriteArrayList 就会被修改,因为 迭代器在 ArrayList 的单独副本上运行。因此所有 在 CopyOnWriteArrayList 上所做的更新不适用于 Iterator。
要获得最新版本,请重新阅读list.iterator();
话虽如此,大量更新此集合会降低性能。如果您尝试对CopyOnWriteArrayList 进行排序,您将看到列表抛出UnsupportedOperationException(排序调用集合上的集合N 次)。仅当您进行超过 90% 的读取时才应使用此读取。
【讨论】:
java.util.concurrent 包而不是Collections.synchronizedList。
synchronized 关键字结合使用时才起作用。
Set 时,我们不需要使用 synchronized 关键字,即使我们使用 Collections.synchronizedList。
应对新数组的目的是什么?
复制底层数组可确保数据结构的任何迭代都是安全的,因为迭代发生在数据的基本不可变“快照”上。
是让其他线程读取数组吗?
有点。更具体地说,每个线程都能够安全地迭代数组,而不必担心ConcurrentModificationException 或其他未知/未定义的行为。
所以如果一个系统是高并发的,并且大部分线程的动作都是读不写,那么最好使用CopyOnWriteArrayList。我说的对吗?
没有。仅当大多数线程的操作是对列表的迭代时。如果大多数活动都是基于随机访问的读取,那么ReadWriteLock 可能会更好。
来自CopyOnWriteArrayList的javadoc
这通常成本太高,但当 遍历 操作的数量远远超过突变时,它可能比替代方法更有效,并且在您不能或不想同步 遍历时很有用>,但需要排除并发线程之间的干扰。
【讨论】:
ReadWriteLock 可能会更好吗?
CopyOnWriteArrayList 用于安全遍历。使用它的代价是为每次修改复制底层引用数组,并可能为迭代结构的陈旧版本的线程保留多个副本。 ReadWriteLock 将允许多个读者,并且仍然允许偶尔的作者执行必要的修改。