简介
本文介绍Java的CopyOnWriteArrayList的原理。
CopyOnWriteArrayList是JUC的一个并发容器,它是个线程安全的ArrayList。
读操作无锁,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略,我们也可以称这种容器为”写时复制器”,JUC中类似的容器还有CopyOnWriteSet(底层是基于CopyOnWriteArrayList实现)。
Write的时候总是要Copy(将原来array复制到新的array,修改后,将引用指向新数组)。任何可变的操作(add、set、remove等)都通过ReentrantLock 控制并发。
优缺点
优点
- 读操作性能很高
- 因为读操作无需任何同步措施,适用于读多写少的并发场景。
- 不会抛出ConcurrentModificationException异常
- list在遍历时,若中途有别的线程对list容器进行修改,则会抛出ConcurrentModificationException异常。而CopyOnWriteArrayList由于其”读写分离”的思想,遍历和修改操作分别作用在不同的list容器,所以在使用迭代器进行遍历时候,也就不会抛出ConcurrentModificationException异常了
缺点
- 内存占用大
- 每次写操作都将原容器拷贝一份,数据量大时,对内存压力较大,可能会引起频繁GC;
- 无法保证实时性
- Vector对于读写操作均加锁同步,可以保证读和写的强一致性
- CopyOnWriteArrayList写和读分别作用在新老不同容器上,在写操作执行过程中,读不会阻塞但读取到的却是老容器的数据。
- 大量写操作性能极差
功能的限制
迭代器没有remove功能
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>(); list.add("aaa"); list.add("bbb"); list.add("ccc"); Iterator<String> iterator = list.iterator(); while(iterator.hasNext()) { String next = iterator.next(); iterator.remove(); }
结果
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(CopyOnWriteArrayList.java:1178) at ConcurrentSet.main(ConcurrentSet.java:47)
不支持Collections.sort(xx, yy)
会报异常:java.lang.UnsupportedOperationException
解决方案
List temp = Arrays.asList(copyOnWriteArrayList.toArray()); Collections.sort(temp); copyOnwriteArrayList.clear(); copyOnWriteArrayList.addAll(temp);
请先
!