Java 并发系列四:CopyOnWriteArrayList 实现原理及源码分析【转载】

When

CopyOnWriteArrayList 是jdk1.5以后并发包中提供的一种并发容器,写操作通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也成为“写时复制容器”,类似的容器还有 CopyOnWriteArraySet。

Why

众所周知,集合框架中的ArrayList 是非线程安全的,Vector虽然是线程安全的,但是处理方式简单粗暴(synchronized),性能较差。而CopyOnWriteArrayList提供了不同的处理并发的思路。

How

很多时候,我们系统中处理的都是读多写少的并发场景。CopyOnWriterArrayList 允许并发的读,读操作是无锁的,性能较高。写操作的话,比如向容器增加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。

img

优缺点分析

了解了CopyOnWriteArrayList原理,接下来分析优缺点及使用场景

优点:

读操作性能很高,因为无需任何同步措施,比较适用于读多写少的并发场景。Java 的 list 在遍历时,若中途有其他线程对容器进行修改,则会抛出ConcurrentModificationException 异常。而CopyOnWriteArrayList由于其“读写分离”的思想,遍历和修改操作分别作用在不同的 list容器,所以迭代的时候不会抛出 ConcurrentModificationExecption 异常了。

缺点:

缺点也很明显,一是内存占用问题,毕竟每次执行写操作都要将原容器拷贝一份,数据量大时,对内存压力较大,甚至可能引起频繁GC,二是无法保证实时性,Vector 对读写操作均加锁同步,可以保证容器的读写强一致性,CopyOnWriteArrayList由于其实现策略的原因,写和读分别作用于不容容器上,在写的过程中,读是不会发生阻塞的,未切换索引置新容器时,是读不到刚写入的数据的。

源码分析

原理理解了,再来分析源码吧~~~~~

public boolean add(E e) {
   //加锁,对写操作保证线程安全
   final ReentrantLock lock = this.lock;
   lock.lock();
   try {
       Object[] elements = getArray();
       int len = elements.length;
       //拷贝原容器,长度为原容器+1
       Object[] newElements = Arrays.copyOf(elements, len + 1);
       //在新副本执行添加操作
       newElements[len] = e;
       //底层数组指向新的数组
       setArray(newElements);
       return true;
   } finally {
       lock.unlock();
   }
}
其中 底层数组定义如下:
private transient volatile Object[] array;
增加内存可见性。

同理可以分析删除操作。

总结

其实并发容器的优缺点,是要根据我们实际的业务场景做出取舍的。

但前提是,你要了解他们各自的优缺点,谢谢!

再一次感谢作者!!

https://www.cnblogs.com/chengxiao/p/6881974.html

你可能感兴趣的:(Java 并发系列四:CopyOnWriteArrayList 实现原理及源码分析【转载】)