CopyOnWriteArrayList學習小結

CopyOnWriteArrayList學習小結

以下內容約600字(不含代碼),預計閱讀需要5分鐘

簡介

CopyOnWriteArrayList類位于java.util.concurrent包,JDK1.5引入,作者為Doug Lea。CopyOnWriteArrayList是一個線程安全的List,使用“寫時復制”的思想在進行所有寫入操作(增加、刪除等)是都會進行內部存儲元素數(shù)組的復制。

代碼分析

寫時過程

由于采用寫時復制的策略,其主要作用過程在于對存儲數(shù)據(jù)進行修改時。以add函數(shù)為例。一下為JDK8中實現(xiàn)源碼:

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();
    }
}
  1. 進入函數(shù)首先獲取ReentrantLock重入鎖[1];
  2. 獲取當前對象中實際存儲數(shù)據(jù)的Object數(shù)組;
  3. 復制當前數(shù)組并且將數(shù)組長度擴展1;
  4. 將新數(shù)據(jù)插入當前數(shù)組的最后一位;
  5. 將指向原數(shù)組的變量置為指向新數(shù)組,釋放鎖,完成工作。

對比ArrayList

增加元素代碼:

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

通過查看代碼可知,ArrayList在寫入時是沒有加鎖的,所以多線程情況下使用并不安全,需要程序員手動進行并發(fā)控制。引用源碼中說明為:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList method. This is best done at creation time, to prevent accidental unsynchronized access to the list:
List list = Collections.synchronizedList(new ArrayList(...));

驗證ArrayList線程不安全可使用以下代碼

public class Main {
    static class AddThread implements Runnable {
        private List<String> list;
        private CountDownLatch countDownLatch;

        public AddThread(List<String> list, CountDownLatch countDownLatch) {
            this.list = list;
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName());
            for(int i=0;i<500;i++){
                list.add("1");
            }
        }
    }

    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            new Thread(new AddThread(list, countDownLatch)).start();
        }
        countDownLatch.countDown();
    }
}

運行過程中大概率會出現(xiàn)Java.lang.ArrayIndexOutOfBoundsException錯誤

優(yōu)點

使用CopyOnWriteArrayList可以不用進行手動同步控制,并且由于使用了讀寫分離的措施,在進行寫入時可以同時進行數(shù)據(jù)的讀取,并且數(shù)據(jù)讀取過程中不需要加鎖。

缺點

根據(jù)其實現(xiàn)代碼,CopyOnWriteArrayList的缺點同樣明顯。首先、其每次寫入都需要進行數(shù)組的復制,所以對于寫入操作非常消耗系統(tǒng)資源,尤其是內存資源,這種情況在處理存儲較多數(shù)據(jù)的List時尤其明顯。對于gc[2]也造成了較大壓力。其次,由于其在讀取時不需要獲取鎖,造成如寫入數(shù)據(jù)同時進行讀取可能造成讀取到的數(shù)據(jù)為舊數(shù)組中的數(shù)據(jù),可能造成數(shù)據(jù)的不一致。

使用場景

由此可見,CopyOnWriteArrayList比較適合用在大量讀取小量寫入的場景,并且要求系統(tǒng)對于數(shù)據(jù)的不一致寬容度較高。
針對寫時復制的策略,在必須要進行寫入時盡量將多次寫入合并為一次寫入,減少數(shù)組復制次數(shù)。


  1. 后續(xù)補充對于重入鎖的介紹 ?

  2. 后續(xù)補充對于gc知識的總結 ?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • java筆記第一天 == 和 equals ==比較的比較的是兩個變量的值是否相等,對于引用型變量表示的是兩個變量...
    jmychou閱讀 1,656評論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,618評論 19 139
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,740評論 18 399
  • WSDL下載 登錄Salesforce,點擊設置,選擇API后選擇對應的WSDL,下載WSDL對應的XML文件。 ...
    小小俊子閱讀 964評論 0 1
  • 最近不是因為聽了一些閑言碎語,之后打算辭職,但是因為年底了還有學校那邊也沒用好的公司,但是還是和邱總說了要回我的就...
    FengNvZi何萍萍閱讀 789評論 0 0

友情鏈接更多精彩內容