前言
项目源代码中使用了CopyOnWriteArrayList类,出于好奇就研究它,看它里面有那些优点,作者设计基于什么考虑,能带来那些好处。
原注释如下
/**
* A thread-safe variant of {@link java.util.ArrayList} in which all mutative
* operations ({@code add}, {@code set}, and so on) are implemented by
* making a fresh copy of the underlying array.
*
* <p>This is ordinarily too costly, but may be <em>more</em> efficient
* than alternatives when traversal operations vastly outnumber
* mutations, and is useful when you cannot or don't want to
* synchronize traversals, yet need to preclude interference among
* concurrent threads. The "snapshot" style iterator method uses a
* reference to the state of the array at the point that the iterator
* was created. This array never changes during the lifetime of the
* iterator, so interference is impossible and the iterator is
* guaranteed not to throw {@code ConcurrentModificationException}.
* The iterator will not reflect additions, removals, or changes to
* the list since the iterator was created. Element-changing
* operations on iterators themselves ({@code remove}, {@code set}, and
* {@code add}) are not supported. These methods throw
* {@code UnsupportedOperationException}.
*
* <p>All elements are permitted, including {@code null}.
*
* <p>Memory consistency effects: As with other concurrent
* collections, actions in a thread prior to placing an object into a
* {@code CopyOnWriteArrayList}
* <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
* actions subsequent to the access or removal of that element from
* the {@code CopyOnWriteArrayList} in another thread.
*
* @since 1.5
* @author Doug Lea
* @param <E> the type of elements held in this list
*/
本人google翻译了其中大部分术语,简单翻译了原文,原文大致是这样的:
CopyOnWriteArrayList是线程安全的ArrayList的变种,它里面是通过底层数组的拷贝来实现更改操作。
通常情况下这种实现是昂贵耗时的,但是当遍历操作变化大时,它比一般方案更高效并且当你不能或不愿去同步遍历数组时,同时必须避免并发线程间干扰时更有用。
“快照”形式迭代器方法使用迭代器创建数组状态引用,数组在迭代器生命周期内永远不会被改变,因此,相互干扰是不会发生的,并且迭代器保证了不抛出并发修改异常,从迭代器创建时,它就不会响应List 的添加、移除和更改。迭代器的更改操作将不支持,调用删除、修改、添加等方法会报不支持操作异常。
内存一致性影响:对比其他并发集合,现场保存对象到CopyOnWriteArrayList中的动作发生在其他线程存储、删除元素操作的前面。
分析
类的源码在这里,因为CopyOnWriteArrayList类是普通ArrayList 的一个变异版本,所以与ArrayList的实现大致相同,本类实现List接口。下面2个变量是实现本列表的关键变量。lock用来同步,elements存储数据,类型是最基础父类 Object,可以添加各种类型的对象,而方法中要适配不同的对象,所以使用了泛型(方法参数带T & E)。
- 关键字volatile的用意是当变量有修改时,所有线程拥有此变量将无效,必须重新获取此变量。
- 关键字transient,修饰的对象将不被序列化(因为本类集成了Serializable接口);
- 迭代器,内部类COWIterator实现了ListIterator接口,迭代器只能访问数组中的元素,不能增加、删除、修改元素(数组中元素的相对位置)。
- 如果对列表进行修改、删除、添加,则这些方法要进行同步检查,全局锁对象lock.
- 子类表类–COWSubList。如果修改子列表的数组,那么要达到同步效果,方法是获取父列表的lock对象,并对方法进行同步。
final transient Object lock = new Object();
private transient volatile Object[] elements;
总结
- 线程安全,表示类中的所有方法对数组进行修改,都要进行同步,防止多线程并发修改。
- 此类有个特别的地方,对数组的修改,都是通过拷贝数组来完成,而不是说在原数组中进行元素移位。另外有个常识—java数组移动比拷贝要慢,因为拷贝是底层实现。
- 序列化。对数组elements不进行序列化,但是要对数组里面的元素进行序列化。
如果您觉得本篇文章很值得,作者很卖力,欢迎任意打赏