并发集合:CopyOnWriteArrayList&CopyOnWriteArraySet
copy on write技术:在写的时候copy(深拷贝)一块内存,在新拷贝的的内存上写,原来的那块内存还可以读,避免了脏读。写完后,把引用指向新内存。
CopyOnWriteArraySet在内部是基于CopyOnWriteArrayList实现的
部分源码
// CopyOnWriteArrayList的add方法
public boolean add(E e) {
// 修改数据的时候加锁,避免多线程同时修改
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
// copy一块新内存
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
// 引用指向新内存
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
// CopyOnWriteArrayList的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;
// 移出最后一个,copy
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
// copy前半段
System.arraycopy(elements, 0, newElements, 0, index);
// copy后半段
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
// 更新引用
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
// CopyOnWriteArrayList的get方法
// get方法是直接返回的,没有加锁,因为读是安全的,不会有线程修改原数组
public E get(int index) {
return get(getArray(), index);
}
private E get(Object[] a, int index) {
return (E) a[index];
}
// CopyOnWriteArraySet中的一个属性
// 一切都明白了
private final CopyOnWriteArrayList<E> al;
适用场景
由于在写数据的时候会有数组拷贝,如果数组特别大,就会产生很多的内存垃圾,所以适合读多写少的场景。
缺点
- 大量数组copy占用内存,提高gc频率
- 不能做到实时读数据(修改的数据不能立刻读到)
优点
- 线程安全
- 读数据速度快(没有加锁)