java多線程之CopyOnWriteArrayList源碼解析

前言

CopyOnWriteArrayList是一個線程安全的ArrayList,對ArrayList內部結構不太清楚的可以看看博主的這篇文章:從源碼分析java容器之ArrayList,看完這篇文章,你會知道爲什麼ArrayList是非線程安全的。然後你再來看這篇文章,看看CopyOnWriteArrayList是如何保證線程安全的。

1、結構圖

在這裏插入圖片描述
從結構圖中,我們可以看出CopyOnWriteArrayList本質上還是一個List,內部數據結構還是數組。

2、分析源碼

2.1、屬性

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8673264195747942595L;
    //增加了一個ReentrantLock互斥鎖
    //我們應該能夠猜到是保證增刪的線程安全,保證了寫的線程安全
    final transient ReentrantLock lock = new ReentrantLock();
	//內部數組增加了volatile修飾
	//增加了數組多線程中在內存的可見性,保證了讀的線程安全
    private transient volatile Object[] array;
    //以下省略……
}

2.2、構造方法

public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}

public CopyOnWriteArrayList(Collection<? extends E> c) {
    Object[] elements = c.toArray();
    if (elements.getClass() != Object[].class)
        elements = Arrays.copyOf(elements, elements.length, Object[].class);
    setArray(elements);
}

public CopyOnWriteArrayList(E[] toCopyIn) {
    setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}

2.3、add()方法

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    //獲取該對象的獨佔鎖(在同一個時間點只能被一個線程鎖持有),保證線程安全
    lock.lock();
    try {
    	//獲取內部數組元素
        Object[] elements = getArray();
        int len = elements.length;
        //創建一個比舊數據長度+1的新數組
        //複製舊數組數據到新數組
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        //將添加的元素放置到數組尾部
        newElements[len] = e;
        //新數組指向Volatile修飾的array
        setArray(newElements);
        return true;
    } finally {
    	//釋放鎖
        lock.unlock();
    }
}

上面的add()方法步驟是:

  1. 先copy舊數組到新數組
  2. 然後寫入新增的元素
  3. 再將新數組指向Volatile修飾的array數組

有木有突然明白爲什麼它叫CopyOnWriteArrayList。

3、總結

  1. CopyOnWriteArrayList內部數據結構是數組。
  2. CopyOnWriteArrayList內部有一個ReentrantLock對象的成員變量lock,lock保證了寫和刪除操作的線程安全。
  3. CopyOnWriteArrayList內部的數組是用Volatile修飾,保證了讀操作的線程安全。
  4. CopyOnWriteArrayList的擴容是每次+1,適合的場景是讀多寫少的場景。

結束語

通過本篇的分析,我們知道了CopyOnWriteArrayList相比ArrayList,如何保證了線程安全。

下一篇,我們將分析CopyOnWriteArraySet的實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章