天天看點

關于CopyOnWriteArrayList的技術了解

前言

項目源代碼中使用了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不進行序列化,但是要對數組裡面的元素進行序列化。

如果您覺得本篇文章很值得,作者很賣力,歡迎任意打賞

關于CopyOnWriteArrayList的技術了解

繼續閱讀