CopyOnWrite容器使用总结

CopyOnWrite容器

如同它的名字一样,在操作容器时候,如果涉及写操作则复制一份拷贝,操作这份拷贝。下面我们以CopyOnWriteArrayList为例子进行说明。

可以从这个类的说明中

A thread-safe variant of java.util.ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.

This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException. The iterator will not reflect additions, removals, or changes to the list since the iterator was created.

可以看到,这个List是线程安全的,而且永远不会抛出ConcurrentModificationException,遇到这种异常的话可以考虑使用CopyOnWrite容器。注意是考虑,后面会讨论它的优缺点。

另外可以看看
http://blog.csdn.net/maxwell_nc/article/details/49301555

谷歌Android源码中的View上的addOnLayoutChangeListener等方法的写法,其中clone集合这种设计方法非常值得借鉴,也可以解决线程安全问题,不会抛出ConcurrentModificationException。

源码分析

回到正题,我们先看看CopyOnWriteArrayList身上的几个方法源码(为了阅读方便,我把部分的源码删减了):

  • get方法:
    public E get(int index) {
        return get(getArray(), index);
    }
  • set方法:
  public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            ...
        } finally {
            lock.unlock();
        }
    }
  • add方法:
public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            ...
        } finally {
            lock.unlock();
        }
    }
  • remove方法:
    public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            ...
        } finally {
            lock.unlock();
        }
    }
  • contains方法:
    public boolean contains(Object o) {
        Object[] elements = getArray();
        return indexOf(o, elements, 0, elements.length) >= 0;
    }
  • indexOf方法:
    public int indexOf(Object o) {
        Object[] elements = getArray();
        return indexOf(o, elements, 0, elements.length);
    }

可以看出,只有在涉及修改容器里的内容时候才会加锁,
而且都有类似下面的语句:

Object[] newElements = Arrays.copyOf(elements, len + 1);

也就说明它的名字CopyOnWrite,当修改时是修改拷贝,而不是原来的List,所以不会出现线程问题。

注意事项

虽然CopyOnWrite容器十分适合解决线程安全问题,但是要注意的是CopyOnWrite容器也要分使用场景:
首先从源码可以看出,只要对容器内容进行修改的话,就会涉及复制数组操作,这无疑大大消耗内存的使用,所以首先使用CopyOnWrite容器必须确保:使用容器的时候的读的操作比写的操作要多,而且容器的大小最好不要太大,否则会出现不断GC。
另外第二点就是,CopyOnWrite容器虽然能够解决多线程问题,但是不能解决数据一致性问题,不能保证数据的实时统一,所以如果用来设计银行业务的朋友就要注意了。

总结

使用CopyOnWrite容器最佳条件:

  • 容器存放少量,并且不涉及频繁写入的情况。
  • 不需要考虑实时数据一致性
  • 多线程才考虑使用,单线程的ConcurrentModificationException可以考虑使用其他的方法。

声明

原创文章,欢迎转载,请保留出处。
有任何错误、疑问或者建议,欢迎指出。
我的邮箱:Maxwell_nc@163.com

参考文章

http://my.oschina.net/xianggao/blog/390390

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值