打赏

CopyOnWrite

CopyOnWrite

  • CopyOnWrite简称COW,是一种程序设计中的优化策略。
  • JDK里COW容器有两种:
    • CopyOnWriteArrayList
    • CopyOnWriteArraySet
  • COW容器非常有用,可以在非常多的并发场景中使用
  • 使用场景,读多写少的时候,容量不大时(Copy操作) 比如缓存
  • 属于读写分离的思想,读和写不同的容器。
CopyOnWrite

写时复制的容器

  • 通俗的讲就是当我们往容器里面添加元素的时候,不直接在当前容器添加,二十先将当前容器进行Copy,复制出一个新的容器,然后往新的容器里面添加元素。
  • 这样做的好处是,我们可以对CopyOnwrite并发的读,而不需要加上,因为不添加任何元素。
源码分析

写操作:add()

private transient volatile Object[] array;

final void setArray(Object[] a) {
    array = a;
}

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();
    }
}
  1. 使用了重入锁,加入有一个线程A,一个线程B,如果线程A正在写,那么线程锁住,等它写完之后线程B才可以写。
  2. getArray()获取当前容器,将当前容器复制到新的容器,再将新的容器复制到当前容器。JVM回收原来的容器。

set操作

同样更新的是一个副本,更新之后再覆盖原来的值,保证了读写分离。

   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;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }
总结
注意:
  • 减少扩容开销。根据实际需要,初始化CopyOnWriteMap的大小,避免写时CopyOnWriteMap扩容的开销。
  • 使用批量添加。因为每次添加,容器每次都会进行复制,所以减少添加次数,可以减少容器的复制次数。如使用上面代码里的addBlackList方法

缺点:

  • 内存占用问题
    • 针对内存占用问题,可以通过压缩容器中的元素的方法来减少大对象的内存消耗,比如,如果元素全是10进制的数字,可以考虑把它压缩成36进制或64进制。或者不使用CopyOnWrite容器,而使用其他的并发容器
  • 数据一致性问题
    • CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。
参考
posted @ 2018-08-02 09:55  JupiterMouse  阅读(492)  评论(0)    收藏  举报