目錄
【1】CopyOnWriteArrayList 簡介
【2】核心原理
1.底層數據結構
2.寫時復制機制
【3】CopyOnWriteArrayList常用方法及實例
1.添加元素方法 add ()
2.獲取元素方法 get ()
3.刪除元素方法remove()
【4】優缺點分析
【5】適用場景
【6】總結
【1】CopyOnWriteArrayList 簡介
????????Copy-On-Write,是一種用于集合的并發訪問優化策略。它的基本思想是:當我們往一個集合容器中寫入元素時(添加、修改、刪除),并不會直接在集合容器中寫入,而是先將當前集合容器進行Copy,復制出一個新的容器,然后新的容器里寫入元素,寫入操作完成之后,再將原容器的引用指向新的容器。
????????這種策略的優點是:實現對CopyOnWrite集合容器寫入操作時的線程安全,但同時并不影響進行并發的讀取操作。所以CopyOnWrite容器也是一種讀寫分離的思想。
????????從JDK1.5開始Java并發包里提供了兩個使用CopyOnWrite機制實現的并發集合容器,它們是CopyOnWriteArrayList和CopyOnWriteArraySet。????????CopyOnWriteArrayList相當于線程安全的ArrayList,內部存儲結構采用Object[]數組,線程安全使用ReentrantLock實現,允許多個線程并發讀取,但只能有一個線程寫入。
【2】核心原理
1.底層數據結構
????????CopyOnWriteArrayList 的底層數據結構是一個數組,使用
volatile
關鍵字修飾以保證可見性:
2.寫時復制機制
CopyOnWriteArrayList 的核心思想是寫時復制(Copy-On-Write):
- 當進行寫操作(添加、修改、刪除)時,首先復制一份當前的底層數組
- 在復制的新數組上執行寫操作
- 操作完成后,將底層數組的引用指向新數組
這種機制保證了讀操作永遠訪問的是一個穩定的數組,不需要加鎖。
【3】CopyOnWriteArrayList常用方法及實例
1.添加元素方法 add ()
????????添加新元素至集合時,會將當前數組Copy復制新數組,并將新元素添加至新數組,最后替換原數組。執行過程中,使用ReentrantLock加鎖,保證線程安全,避免多個線程復制數組。
public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;// 復制出新數組Object[] newElements = Arrays.copyOf(elements, len + 1);// 把新元素添加到新數組里newElements[len] = e;// 把原數組引用指向新數組setArray(newElements);return true;} finally {lock.unlock();} }
2.獲取元素方法 get ()
????????根據指定下標,到原數組中讀取元素。讀取過程中不加鎖,允許多個線程并發讀取。但是如果讀取的時候,有其它線程同時向集合中添加新元素并未結束,get()方法仍然讀取到的是舊數據。
public E get(int index) {// 根據指定下標,從原數組中讀取元素return get(getArray(), index); }private E get(Object[] a, int index) {return (E) a[index]; }
3.刪除元素方法remove()
????????刪除指定下標元素。根據指定下標,從原數組中,Copy復制其它元素至新數組,最后替換原數組。
public E remove(int index) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;E oldValue = get(elements, index);int numMoved = len - index - 1;if (numMoved == 0)// 復制原數組中,除最后一個元素以外的所有元素,至新數組setArray(Arrays.copyOf(elements, len - 1));else {// 復制原數組中,除刪除元素以外的所有元素,至新數組Object[] newElements = new Object[len - 1];System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index + 1, newElements, index,numMoved);setArray(newElements);}return oldValue;} finally {lock.unlock();} }
【4】優缺點分析
優點
讀操作性能優異:讀操作無需加鎖,適合讀多寫少的場景
迭代安全:迭代過程中不會拋出ConcurrentModificationException
線程安全:通過寫時復制和鎖機制保證線程安全
缺點
內存占用:寫操作時需要復制整個數組,可能導致內存占用翻倍
數據一致性:只能保證最終一致性,不能保證實時一致性
寫操作性能差:每次寫操作都需要復制數組,開銷較大
【5】適用場景
CopyOnWriteArrayList 適用于以下場景:
讀多寫少的并發場景,如緩存、配置信息管理
需要避免迭代過程中ConcurrentModificationException的場景
數據量不大的場景(避免復制大數組帶來的性能開銷)
不適合的場景:
寫操作頻繁的場景
對數據實時一致性要求高的場景
存儲大量數據的場景
【6】總結
????????CopyOnWriteArrayList 通過獨特的寫時復制機制,在特定場景下提供了高效的并發處理能力。它不是萬能的,但是在讀多寫少的場景下,相比傳統的同步列表實現具有明顯的優勢。
????????感謝你花時間讀到這里~ 如果你覺得這篇內容對你有幫助,不妨點個贊讓更多人看到;如果有任何想法、疑問,或者想分享你的相關經歷,歡迎在評論區留言交流,你的每一條互動對我來說都很珍貴~ 我們下次再見啦!😊😊