前言
項目源代碼中使用了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" target="_blank" rel="external nofollow" ><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不進行序列化,但是要對數組裡面的元素進行序列化。
如果您覺得本篇文章很值得,作者很賣力,歡迎任意打賞