CopyOnWriteArrayList小结

362 阅读1分钟

实现原理

  • 使用ReentrantLock加锁
  • 底层复制新的数组,对新数组操作,然后将新数组的引用设置给集合
public E set(int index, E element) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // 得到原数组的旧值
        Object[] elements = getArray();
        E oldValue = get(elements, index);
        // 判断新值和旧值是否相等
        if (oldValue != element) {
            // 复制新数组,新值在新数组中完成
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len);
            newElements[index] = element;
            // 将array引用指向新数组
            setArray(newElements);
        } else {
            // Not quite a no-op; enssures volatile write semantics
            setArray(elements);
        }
        return oldValue;
    } finally {
        lock.unlock();
    }
}

缺点

  • 内存占用:如果CopyOnWriteArrayList经常要增删改里面的数据,经常要执行add()、set()、remove()的话,那是比较耗费内存的。

    • 因为我们知道每次add()、set()、remove()这些增删改操作都要复制一个数组出来。
  • 数据一致性:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性

    • 从上面的例子也可以看出来,比如线程A在迭代CopyOnWriteArrayList容器的数据。线程B在线程A迭代的间隙中将CopyOnWriteArrayList部分的数据修改了(已经调用setArray()了)。但是线程A迭代出来的是原有的数据。