顧名思義,採用寫時複製技術,讀的時候不加鎖,寫數據的時候先加鎖,把當前數據複製一份進行寫操作,寫完畢後替換當前的數據,然後釋放鎖。
這種集合適用於讀多寫少的場景。寫數據的時候比較佔空間,典型的拿控件換時間。
常用的集合有
CopyOnWriteArrayList
CopyOnWriteArraySet
1 CopyOnWriteArrayList
首先看add方法
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();
}
}
remove方法
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();
}
}
get方法
get方法沒什麼特別注意的,根據下標取元素即可
2 CopyOnWriteArraySet
CopyOnWriteArraySet底層就是CopyOnWriteArrayList。有人會說不對啊,set是不能重複的,list是可以重複的。你忽悠我?
源碼走起
首先看一下構造函數,look
private final CopyOnWriteArrayList<E> al;
/**
* Creates an empty set.
*/
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
可以看到CopyOnWriteArraySet初始化的時候就是初始化了一個CopyOnWriteArrayList
來看一下它的add方法是怎麼實現的
public boolean add(E e) {
return al.addIfAbsent(e);
}
對,你沒有看錯,它的add方法實際上就是調用的CopyOnWriteArrayList.addIfAbsent方法,沒有的時候才添加。
然後你在看CopyOnWriteArraySet的其他方法
public boolean contains(Object o) {
return al.contains(o);
}
public boolean containsAll(Collection<?> c) {
return al.containsAll(c);
}
public boolean addAll(Collection<? extends E> c) {
return al.addAllAbsent(c) > 0;
}
public boolean remove(Object o) {
return al.remove(o);
}
調用的都是CopyOnWriteArrayList的原生方法。換句話說,如果你不用CopyOnWriteArrayList的add方法,添加元素的時候只用addIfAbsent,那它就是一個CopyOnWriteArraySet