论证 CopyOnWriteArrayList 如何成为线程安全的 ArrayList


> 我不停奔跑只为追赶当年被寄予厚望的自己。
> ——利文斯顿

Q:来,介绍下

ArrayList 的一个线程安全的变体,在这个变体中,所有突变操作(add、set等)都是通过对底层数组的做一份新的拷贝来实现的。

这种方式通常成本太高,但当遍历操作的数量远远超过突变操作时,可能比其他方法更高效,而且当你不能或不想同步遍历,但又需要避免并发线程之间的干扰时,这种方式很有用。“快照” 风格的迭代器方法使用了一个引用来创建迭代器时的数组状态。这个数组在迭代器的生命周期内永远不会改变,所以干扰是不可能的,并且保证迭代器不会抛ConcurrentModificationException。迭代器创建后,不会反映列表的添加、删除或更改。不支持对迭代器本身进行元素改变操作(remove,set,add)。这些方***抛出UnsupportedOperationException。

所有元素都是允许的,包括null。

内存一致性的影响。与其他并发集合一样,在将对象放入CopyOnWriteArrayList(后文简称 COW)之前,线程中的操作会在另一个线程中的CopyOnWriteArrayList中访问或删除该元素的后续操作之前发生。

这个类也是Java集合框架中的一个成员。

Q:那你先说说他具体是怎么保证线程安全的吧?

  • 写时复制策略
    如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作时可以共享同一份资源。

我们必定要从写入手,看看写时到底做了什么,看实现了 List 接口下最传统的 add 方法:

注意在向 COW 里添加元素时是需要加锁的,否则会 copy 出N个副本。

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    // 加锁
    lock.lock();
    try {
       

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java源码模拟面试解析指南 文章被收录于专栏

<p> “挨踢”业行情日益严峻,企业招聘门槛愈来愈高,大厂hc更是少之又少,而Java技术面试普遍对基础知识的掌握考察特别深,大多数同学突击所看的 Java 面试基础知识点根本达不到面试官近乎挑剔的要求。 本专刊针对如今的校招及社招痛点,深入解析 JDK 的核心源码,探究 JDK 的设计精髓及最佳实践,同时以模拟面试的场景切入,让同学们在阅读过程中也能轻松掌握面试技巧。 本专刊购买后即可解锁所有章节,故不可以退换哦~ </p>

全部评论

相关推荐

09-17 19:25
已编辑
太原理工大学 游戏测试
叁六玖:公司名发我,我要这个HR带我打瓦
我的秋招日记
点赞 评论 收藏
分享
美丽的95后准备进厂:第二个是外卖➕点评吧,很眼熟
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务