CopyOnWriteArrayList

CopyOnWriteArrayList

四个关注点

关 注 点 结 论
CopyOnWriteArrayList是否容许空 容许
CopyOnWriteArrayList是否容许重复数据 容许
CopyOnWriteArrayList是否有序 有序
CopyOnWriteArrayList是否线程安全 线程安全

首先提两点:java

一、CopyOnWriteArrayList位于java.util.concurrent包下,可想而知,这个类是为并发而设计的数据库

二、CopyOnWriteArrayList,顾名思义,Write的时候老是要Copy,也就是说对于CopyOnWriteArrayList,任何可变的操做(add、set、remove等等)都是伴随复制这个动做的,后面会解读CopyOnWriteArrayList的底层实现机制数组

对于CopyOnWriteArrayList来讲,增长、删除、修改、插入的原理都是同样的,话很少说,用源码和图进行演示:缓存

1 public static void main(String[] args)
2 {
3     List<Integer> list = new CopyOnWriteArrayList<Integer>();
4     list.add(1);
5     list.add(2);
6 }

源码安全

public boolean add(E 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();
}
}

每一步都清楚地表示在图上了,一次add大体经历了几个步骤:并发

一、加锁分布式

二、拿到原数组,获得新数组的大小(原数组大小+1),实例化出一个新的数组来高并发

三、把原数组的元素复制到新数组中去this

四、新数组最后一个位置设置为待添加的元素(由于新数组的大小是按照原数组大小+1来的)atom

五、把Object array引用指向新数组

六、解锁

整个过程看起来比较像ArrayList的扩容。有了这个基础,咱们再来看一下第5行的add了一个整数2作了什么,这应该很是简单了,仍是画一张图来表示:

另外,插入、删除、修改操做也都是同样,每一次的操做都是以对Object[] array进行一次复制为基础的,若是上面的流程看懂了,那么研究插入、删除、修改的源代码应该不难。

为何要用CopyOnWriteArrayList而不用其余的?

这个就和 原子性一致性 有关,ArrayList 和 linkedList 首先线程不安全就不知足,还有一种vector ,虽说线程是安全的,可是不是绝对的安全,只是在单独的增、删、改时能够,可是在组合的时候就不行,因此这里应用了CopyOnWriteArrayList,说下它的优缺点:

缺点:安全性高那效率确定就不高,修改代价十分昂贵,每次修改都伴随着一次的数组复制;但同时优势也十分明显,就是在并发下不会产生任何的线程安全问题,也就是绝对的线程安全,这也是为何咱们要使用CopyOnWriteArrayList的缘由。

优势:

(1)读写分离

咱们读取CopyOnWriteArrayList的时候读取的是CopyOnWriteArrayList中的Object[] array,可是修改的时候,操做的是一个新的Object[] array,读和写操做的不是同一个对象,这就是读写分离。这种技术数据库用的很是多,在高并发下为了缓解数据库的压力,即便作了缓存也要对数据库作读写分离,读的时候使用读库,写的时候使用写库,而后读库、写库之间进行必定的同步,这样就避免同一个库上读、写的IO操做太多

(2)最终一致

对CopyOnWriteArrayList来讲,线程1读取集合里面的数据,未必是最新的数据。由于线程二、线程三、线程4四个线程都修改了CopyOnWriteArrayList里面的数据,可是线程1拿到的仍是最老的那个Object[] array,新添加进去的数据并无,因此线程1读取的内容未必准确。不过这些数据虽然对于线程1是不一致的,可是对于以后的线程必定是一致的,它们拿到的Object[] array必定是三个线程都操做完毕以后的Object array[],这就是最终一致。最终一致对于分布式系统也很是重要,它经过容忍必定时间的数据不一致,提高整个分布式系统的可用性与分区容错性。固然,最终一致并非任何场景都适用的,像火车站售票这种系统用户对于数据的实时性要求很是很是高,就必须作成强一致性的。

最后总结一点,随着CopyOnWriteArrayList中元素的增长,CopyOnWriteArrayList的修改代价将愈来愈昂贵,所以,CopyOnWriteArrayList适用于读操做远多于修改操做的并发场景中

相关文章
相关标签/搜索