什么是CopyOnWrite容器呢?CopyOnWrite容器是一个写时复制的容器。在向容器中添加元素时,不会直接向当前容器中添加,而是将当前容器进行copy,复制出一个新的容器,然后往新的容器中添加元素,添加完元素之后,再将容器的引用指向新的容器。使得我们可以对CopyOnWrite容器进行并发的读而不需要加锁,采用了读写分离的思想,写时复制的策略 使用的场景是读多写少的时候使用,如redis、Linux的文件管理系统等 以CopyOnWriteArrayList为例 CopyOnWriteArrayList是同步List的并发替代品,是java并发包java.util.concurrent中提供的用于并发操作且线程安全的ArrayList,可以提供更好的并发性,并且避免了在迭代期间对容器加锁和复制,在每次修改的时,会创建一个新的容器拷贝,以此来实现可变性 实际是对底层数组的复制操作 每次容器改变对于基础数组的复制也是有一定开销的,特别是当容器较大时,所以该种方式比较适合于读取操作的次数远大于修改操作的次数时才适用 但是对于获取操作并不会进行加锁,而是直接进行获取 所以可能在进行读取的时候获取到的数据并不准确,这是写时复制策略产生的弱一致性问题CopyOnWrite容器
基本思路
CopyOnWriteArrayList
// 存放具体的元素
private transient volatile Object[] array;
// 独占锁用来保证同时只有一个线程对array进行修改
final transient ReentrantLock lock = new ReentrantLock(); public E set(int index, E element) {
// 获取独占锁,写入时加锁,保证只有一个线程在写,防止多线程时copy多份副本
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 获取array
Object[] elements = getArray();
E oldValue = get(elements, index);
// 值修改时
if (oldValue != element) {
int len = elements.length;
// 根据原来的数组拷贝一个新的数组
Object[] newElements = Arrays.copyOf(elements, len);
// 对新的数组调整赋值
newElements[index] = element;
// 原数组的引用指向新数组,替换掉之前的数组
setArray(newElements);
} else {// 值没有修改
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}final Object[] getArray() {
return array;
}
public E get(int index) {
return get(getArray(), index);
}
private E get(Object[] a, int index) {
return (E) a[index];
}优缺点
优点
缺点
本文由 mdnice 多平台发布
标签:index,CopyOnWrite,容器,lock,并发,复制,数据 From: https://blog.csdn.net/Lxn2zh/article/details/136986811