之前介绍了ArrayList,他是在单线程下使用的集合,本文介绍下他的多线程版本CopyOnWriteArrayList。
首先来看实例变量
lock是后续add等操作需要的锁对象,array则为存放元素的
容器。这里注意array为volatile类型,这意味着每次读取array时不需要进行加锁操作,读取的是主存中最新的值。
所以get操作就比较简单了,就是直接获取数组中对应的下标元素。
接下来看set操作,set操作需要改变数组,所以这时就需要加锁了
可以看到,他对整个操作进行了加锁处理防止并发问题。由图可知,每次进行替换的时候都会重新copy一个新的数组,并调用setArray将其赋值给实例变量。这也是CopyOnWrite名称的由来,即写时复制。
其他操作诸如add,remove等都是一样的思路,代码就不贴出来了。
CopyOnWriteArrayList的doc文档上有说,所有可变操作通过生成数组的副本来实现,这样做诚然代价比较高,而当读取操作的行为发生频率远高于可变操作时,这种形式效率就比较高了。所以CopyOnWriteArrayList的使用场景是读多写少。
写时复制的方式解决了多线程同时读取写入读取不需要加锁的问题,然而这会引发其他的问题,因为写时内存中数组可能有俩份,一份旧数组,一份新数组,写入时array变量引用还未指向新数组时,另一线程进行读操作,这时读取操作使用的是旧数组,读取到的可能就是旧数据,导致数据的不一致,所以CopyOnWriteArrayList只能保证最终数据一致性,而非实时一致性,使用的时候需要注意。