多线程总结:CopyOnWriteArrayList (COW)

CopyOnWriteArrayList这是一个ArrayList的线程安全的变体。

 

 原理大概可以通俗的理解为:

  初始化的时候只有一个容器,长时间内容器数据、数量等没有发生变化的时候,多个线程都是读取(假设这段时间里只发生读取的操作)同一个容器中的数据,所以这样大家读到的数据都是唯一、一致、安全的。

  往里面增加数据:CopyOnWriteArrayList 底层实现添加的原理是先copy出一个容器(可以简称副本),再往新的容器里添加这个新的数据,最后把新的容器的引用地址赋值给了之前那个旧的的容器地址,但是在添加这个数据的期间,其他线程如果要去读取数据,仍然是读取到旧的容器里的数据。 

设计思想:

  CopyOnWriteArrayList 就是通过 Copy-On-Write(COW),即写时复制的思想来通过延时更新的策略来实现数据的最终一致性,并且能够保证读线程间不阻塞。

  COW 通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行 Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。
  对 CopyOnWrite 容器进行并发的读的时候,不需要加锁,因为当前容器不会添加任何元素。
  所以 CopyOnWrite 容器也是一种读写分离的思想, 延时更新的策略是通过在写的时候针对的是不同的数据容器来实现的,放弃数据实时性达到数据的最终一致性

缺点:

   1、内存占用问题;

   2、数据不能实时一致性:基于add时先行拷贝副本再修改引用的实现,所以CopyOnWrite 容器只能保证数据的最终一致性,不能保证数据的实时一致性。

 应用场景:

  随着元素数量和线程数量增加,CopyOnWriteArrayList在增加元素和删除元素时的性能下降非常明显,并且性能会比ArrayList低。

  但在查找元素这点上随着线程数的增长,性能较ArrayList会好很多。例如在元素数量为1000、线程数量为100时,CopyOnWriteArrayList查找元素的性能大概为ArrayList的4倍。

  根据这样的运行结果,在读多写少的并发场景中,CopyOnWriteArrayList较之ArrayList是更好的选择

关键代码:

  get:get(int index) 没有加任何锁和同步机制

                

   add:新增元素场景,会进行新数据的创建和拷贝;数组元素越大,耗时约久,性能越差

           数组引用是 volatile 修饰的,因此将旧的数组引用指向新的数组,根据 volatile 的 happens-before 规则,写线程对数组引用的修改对读线程是可见的。

          


 使用样例: 

猜你喜欢

转载自www.cnblogs.com/clarino/p/12804072.html