CopyOnWriteArrayList实现原理

来源:互联网 发布:北京数据分析师招聘 编辑:程序博客网 时间:2024/05/26 09:57

引言

《Java并发编程实战》P43中提到:“通过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或者synchronizedSet中,可以将元素安全的发布到任何从这些容器中访问该元素的线程”。

源码分析

另外,我们知道CopyOnWriteArrayList适用于写少读多的并发场景。那么不妨从源码分析其实现原理。
1.添加时候需要加锁,否则多线程同时写会Copy多个副本。

/***Appends the specified element to the end of this list;@return <tt>true</tt> (as specified by {@link Colelction#add})*/public boolean add(T 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();    }}

2.读的时候不需要加锁,此时如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的copyOnWriteArrayList。

public T get(int index){    return get(getArray(),index);}

总结

虽然CopyOnWriteArrayList保证了写少读多并发线程下元素的安全发布,但是存在两个缺点:
1>内存占用问题。因为CopyOnWrite的写时复制机制,写操作的时候内存会同时驻扎两个对象的问题(复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存)。如果这些内存比较大,可能会造成Yong GC和Full GC。系统如果使用了CopyOnWrite机制更新大对象,容易造成每Full GC,应用响应时间也随之变长。针对内存占用问题,可以通过压缩容器中的元素的方法来减少大对象的内存消耗,比如,如果元素全是10进制的数字,可以考虑把它压缩成36进制或64进制。或者不使用CopyOnWrite容器,而使用其他的并发容器,如ConcurrentHashMap
2> 数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器
注:参考自《Java并发编程实战》、牛客网、blog:http://www.cnblogs.com/dolphin0520/p/3938914.html。

原创粉丝点击