Welcome to Ray's Blog

Stay Hungry Stay Foolish - Steve Jobs

0%

CopyOnWriteArrayList 笔记


概述

CopyOnWriteArrayListArrayList的一个线程安全的变体,其中所有可操作方法(add/set 等)都是通过底层数组进行一次新的复制来实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* A thread-safe random-access list.
*
* <p>Read operations (including {@link #get}) do not block and may overlap with
* update operations. Reads reflect the results of the most recently completed
* operations. Aggregate operations like {@link #addAll} and {@link #clear} are
* atomic; they never expose an intermediate state.
*
* <p>Iterators of this list never throw {@link
* ConcurrentModificationException}. When an iterator is created, it keeps a
* copy of the list's contents. It is always safe to iterate this list, but
* iterations may not reflect the latest state of the list.
*
* <p>Iterators returned by this list and its sub lists cannot modify the
* underlying list. In particular, {@link Iterator#remove}, {@link
* ListIterator#add} and {@link ListIterator#set} all throw {@link
* UnsupportedOperationException}.
*
* <p>This class offers extended API beyond the {@link List} interface. It
* includes additional overloads for indexed search ({@link #indexOf} and {@link
* #lastIndexOf}) and methods for conditional adds ({@link #addIfAbsent} and
* {@link #addAllAbsent}).
*/

该方法一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可可能比其他替代方法更有效。在不能或不想进行同步遍历,但是有需要从并发线程中排出冲突时,它也很有用。“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内不会更改,因此不可能发生冲突,并且迭代器保证不会抛出ConcurrentModificationException错误。创建迭代器以后,迭代器就不会反应列表的添加、移除或者更改信息了。在迭代器上进行的元素更改操作(如remove,·set·和·add·等)不受支持。这些方法将抛出UnspportedOperationException异常。
该类与 ArrayList 最大的区别就是add(E)的时候。容器会自动 copy 一份新数组出来然后在新数组尾部add(E)

1
2
3
4
5
6
7
 public synchronized boolean add(E e) {
Object[] newElements = new Object[elements.length + 1];
System.arraycopy(elements, 0, newElements, 0, elements.length);
newElements[elements.length] = e;
elements = newElements;
return true;
}

总结

CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景中,比如缓存。发生修改时候做 copy,新老版本数组分离,保证读的高性能,适用于以读为主的情况。