目录
一、基本思想
首先CopyOnWrite 简称 COW ,是一种用于对集合并发访问的优化策略。基本思想是:当我们往一个集合容器中写入元素时(比如添加、修改、删除),并不会直接在集合容器中写入,而是先将当前集合容器进行Copy复制,复制出一个新的容器,然后在新的容器里写入元素,写入操作完成之后,再将原容器的引用指向新的容器。
好处是:保证了对 CopyOnWrite 集合容器写入操作时的线程安全,但同时并不会影响进行并发的读取操作。所以 CopyOnWrite 容器也是一种读写分离的思想。CopyOnWriteArrayList 相当于线程安全的 ArrayList ,内部存储结构采用 Object[] 数组,线程安全使用 ReentrantLock 加锁实现,允许多个线程并发读取,但只能有一个线程写入。
二、源码分析
add()方法
添加新元素至集合时,会将当前数组Copy复制到新数组,并将新元素添加至新数组,最后替换原数组。执行过程中,使用ReentrantLock加锁,保证线程安全,避免多个线程复制数组。
set()方法
根据指定下标修改元素值,复制到新数组,在新数组中修改值,最后替换原数组。执行过程中,使用ReentrantLock加锁,保证线程安全,避免多个线程修改数组元素的值。
remove()方法
删除指定下标元素。根据指定下标,从原数组中Copy复制其它元素至新数组,最后替换原数组。
get()方法
根据指定下标,到原数组中读取元素。读取过程中不加锁,允许多个线程并发读取。但是如果读取的时候,有其它线程向集合中添加新元素,此时仍然读取到的是旧数据。因为添加操作没有对原数组加锁。
三、小结
CopyOnWriteArrayList具有以下特性:
- 在保证并发读取的前提下,确保了写入时的线程安全,使用ReentrantLock加锁;
- 由于每次写入操作时,进行了Copy复制原数组,所以无需扩容,复制就是一种简单的扩容;
- 适合读多写少的应用场景,比如缓存。由于add()、set() 、 remove()等修改操作需要复制整个数组,所以会有内存开销大的问题。所以在有写操作的情况下,CopyOnWriteArrayList性能不佳,而且如果容器容量较大的话容易造成溢出。
- CopyOnWriteArrayList由于只在写入时加锁,所以只能保证数据的最终一致性,不能保证数据的实时一致性。
以上就是对于线程安全集合:CopyOnWriteArrayList源码分析的分享,如有不当之处还请大家多多评论指正,喜欢文章的可以留下您的关注和点赞,一起学习,一起加油!