When
CopyOnWriteArrayList 是jdk1.5以后并发包中提供的一种并发容器,写操作通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也成为“写时复制容器”,类似的容器还有 CopyOnWriteArraySet。
Why
众所周知,集合框架中的ArrayList 是非线程安全的,Vector虽然是线程安全的,但是处理方式简单粗暴(synchronized),性能较差。而CopyOnWriteArrayList提供了不同的处理并发的思路。
How
img很多时候,我们系统中处理的都是读多写少的并发场景。CopyOnWriterArrayList 允许并发的读,读操作是无锁的,性能较高。写操作的话,比如向容器增加一个元素,则首先将当前容器复制一份,然后在新副本上执行写操作,结束之后再将原容器的引用指向新容器。
优缺点分析
了解了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; 增加内存可见性。
同理可以分析删除操作。
总结
其实并发容器的优缺点,是要根据我们实际的业务场景做出取舍的。
但前提是,你要了解他们各自的优缺点,谢谢!
网友评论