新建
private transient volatile Object[] array;//底層數據
添加數據
- 先上同步鎖
- 對原始數組進行拷貝(淺拷貝),然後在拷貝後的數組上進行修改
- 將修改後的結果賦值給array
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();
}
}
獲取數據
- 獲取的時候沒有加鎖(由於array是volatile,所以會先從主內存更新數據,所以線程中的數據應該始終都是最新的)
刪除數據
- 先上同步鎖
- 對原始數據進行拷貝,在拷貝的時候不拷貝那個需要刪除的數據
- 將修改後的結果賦值給array
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();
}
}
遍歷數據
- 使用listIterator()獲取迭代器
- listIterator()中將array賦給COWIterator(實現了ListIterator)。這裏沒有進行復制
- 可以調用hasNext() hasPrevious() next() previous()
- 注意:set() add() remove()都會直接拋出異常UnsupportedOperationException
總結
- 由於每次刪除和增加元素都會拷貝一個新的數組出來,因此原本數組中的元素已經過時。所以即使這個時候另一個線程修改數據,也不會報錯,只是數據不是最新的
- 增刪改上鎖、讀不上鎖
- 由於每一次修改都會有新的數組,array使用volatile修飾,所以在讀的時候能確保使用的到的是最新的數組副本(多線程的情況下始終都是在主內存中讀取)
參考jdk1.8源碼
https://www.cnblogs.com/java-zhao/p/5121944.html