CopyOnWrite 浅层次总结

同 ConcurrentHashMap 一样,CopyOnWrite 也是一种多线程并发中使用的容器,实现起来要比 ConcurrentHashMap 简单不少。从 JDK1.5 开始 Java 并发包里提供了两个使用 CopyOnWrite 机制实现的并发容器,它们是 CopyOnWriteArrayList 和 CopyOnWriteArraySet。CopyOnWrite 容器非常有用,可以在非常多的并发场景中使用到,下面就来浅层次总结一下。

源码解析

CopyOnWrite 根据名字,即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行 Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对 CopyOnWrite 容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以 CopyOnWrite 容器也是一种读写分离的思想,读和写不同的容器。

看一下它的 add 方法就比较清晰了,如下:

    public synchronized boolean add(E e) {
        // 新开辟一个长度为原 length + 1 的对象数组
        Object[] newElements = new Object[elements.length + 1];
        // 将原 elements 数组中的内容全部复制到 newElements 数组中
        System.arraycopy(elements, 0, newElements, 0, elements.length);
        // 在 newElements 末尾添加新的元素 e
        newElements[elements.length] = e;
        // 将修改后的数组赋值给原 elements 数组
        elements = newElements;
        return true;
    }

另外也需要注意这个方法是同步的,否则多线程写的时候会 Copy 出 N 个副本出来。

下面,至于读方法,真是再简单不过了,如下:

    public E get(int index) {
        return (E) elements[index];
    }

读的时候不需要加锁,如果读的时候有多个线程正在向 newElements[] 添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的 elements[]。

应用场景

CopyOnWrite并发容器用于读多写少的并发场景。比如白名单,黑名单。

注意问题

  • 内存占用问题:因为 CopyOnWrite 的写时复制机制,所以在进行写操作的时候,内存里会同时驻扎两个对象的内存,旧的对象和新写入的对象(注意:在复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存)。如果这些对象占用的内存比较大,那么这个时候很有可能造成频繁的 Young GC 和 Full GC。

  • 数据一致性问题:CopyOnWrite 容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果希望写入的的数据马上能读到,就不要使用 CopyOnWrite 容器。

个人GitHub: http://github.com/icodeu

个人网站: http://icodeyou.com

个人微信号:qqwanghuan 技术交流

image

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值