Java容器源码重点回顾——CopyOnWriteArrayList

news2025/1/13 3:01:10

1. CopyOnWriteArrayList概述

之前介绍过ArrayList,但是我们知道ArrayList是线程不安全的。如果多个线程同时写数据,就会抛出ConcurrentModificationException。然后我们又学过Vector,它的实现方式是在方法中都加入synchronized关键字,但是这会导致效率低下,并且只有原子方法下能够保证线程安全。

后面,我们又学习了锁,比较常用的是ReentrantLock。为了适用读多写少的场景,出现了ReentrantReadWriteLock。虽然相比于ReentrantLock,ReentrantReadWriteLock虽然在一定程度上提高了读写性能,比较适合读多写少的场景,但是在有线程持有写锁的时候,读线程还是会被阻塞

因此,CopyOnWriteArrayList就是针对了读写场景下互斥的缺陷,进行优化。它在每次需要进行修改的时候,先拷贝一份原来的数组,在拷贝的新数组上进行修改,最后再将引用指向新数组。这样就能保证,有线程在修改时,读线程不会被阻塞。提高了读写的性能。

但是,它也有缺陷

  1. 每次更新都要拷贝原来的数组,如果原数组比较大,就会占用2倍的空间;
  2. 无法做到实时一致性,只能做到最终一致性。因为在新数组上进行修改时,读线程是没法感知的。只有更新了引用的指向之后,才能获取到最新值。

2. 成员变量

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    // 控制写操作线程安全的锁
    final transient ReentrantLock lock = new ReentrantLock();

    // 用来存储数据的数组
    private transient volatile Object[] array;
}

CopyOnWriteArrayList的成员变量很简单,只有两个。

  • lock: 这个成员变量是用来保证写线程的线程安全的,要保证在同一个时刻,不能有多个线程修改数组;
  • array:这个成员变量是用来存储数据的。需要特别注意的是它使用volatile进行修饰,这个会在后面进行讲解。

3. get方法

    public E get(int index) {
        return get(getArray(), index);
    }

    final Object[] getArray() {
        return array;
    }

    private E get(Object[] a, int index) {
        return (E) a[index];
    }

CopyOnWriteArrayList的get方法我们可以看到很简单,也不需要加锁什么的,就是简单地从数组读取返回,因为写线程并不会操作原来的数组。

4. add方法

    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方法中,我们可以看到首先会使用ReentrantLock进行加锁,这是为了保证写线程的线程安全,避免多个写线程复制多次数组。然后就在新数组上进行修改,修改完成后再将指针指向新数组。add方法流程如下图:

在这里插入图片描述

需要注意的是:之前讲过array数组是使用volatile修饰的,根据volatile的happens-before规则,写线程对于数组的引用修改是对于读线程可见的。 这里的volatile只能保证引用修改的可见性,不能保证数组元素修改的可见性。所以读线程并不能立马感知到修改,可能会隔好几秒才能感知到。

参考文章:并发容器之CopyOnWriteArrayList

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94383.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

selenium自动测试常用脚本

一、控制已经打开页面的浏览器&#xff08;已登录状态&#xff09; 1、简述&#xff1a; 自动化执行时&#xff0c;一些页面操作需要用户是登录状态才能进行访问。如果每次运行自动化脚本都需要重新登录、输入短信验证码&#xff0c;不利于自动化快速运行。因此&#xff0c;需…

[附源码]Python计算机毕业设计高校学生宿舍管理信息系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

C语言易错的选择判断题解析

有定义语句&#xff1a;int a10;&#xff0c;则表达式a的值是10。 ( A ) A.正确 B.错误 以下程序段完全正确的是( A ) A.int k, *p&k; scanf(“%d”,p); B.int k,*p: *p&k;scanf(“%d”,p); C.int *p;scanf(“%d”,p); D.51 以下程序段运行后&#xff0c;循环体运行…

Java发布和溢出简述

发布和溢出前言前置知识发布溢出简述类型案例环境发布溢出溢出类型1——未完全初始化就企图获取该对象中数据溢出类型2——在构造函数中调用非private和final的方法前言 回顾《Java并发编程实战》&#xff0c;这里附上一些总结和小案例加深理解。这里重点是对溢出的阐释。 前…

差分约束

前置知识: 最短路问题、SPFA判环&#xff0c;为了保证学习效果&#xff0c;请保证已经掌握前置知识之后&#xff0c;再来学习本章节&#xff01; 引出 当我们遇到一个不等式组&#xff0c;比如下面这个 \begin{cases} x_{1}-x_{3} \leq 5 \\ x_{1}-x_{2} \leq 2 \\ x_{2}-x_{…

3.2 图像分类

文章目录LeNet&#xff08;小图像&#xff09;LeNet在手写数字识别上的应用LeNet在眼疾识别数据集iChallenge-PM上的应用数据集准备查看数据集图片定义数据读取器启动训练AlexNet&#xff08;大图像&#xff09;VGG&#xff08;深度&#xff09;GoogLeNet&#xff08;深度兼广度…

苹果电脑怎么用移动硬盘ntfs?快速读取和编辑Mac外置移动硬盘

苹果电脑怎么用移动硬盘ntfs&#xff1f;如果你对电脑比较熟悉的话&#xff0c;可能知道NTFS磁盘格式。该格式专门为Windows系统设计的&#xff0c;也称为Windows NT文件系统。从Windows系统迁移到Mac可能是一项相当困难的任务&#xff0c;因为NTFS格式的硬盘在Mac上不能正常工…

音视频面试涨知识(一)

1 直播中为什么会出现花屏、黑屏、闪屏&#xff1f; 主播没有打开摄像头权限&#xff0c;推流端没有做好权限校验处理。 采集Camera数据&#xff0c;就要开始编码&#xff0c;如果编码失败&#xff0c;没有推送数据&#xff0c;那就会黑屏。 拉流段遇到不支持的视频格式&…

某讯滑块验证码反汇编分析-第二章

某讯滑块验证码反汇编分析-第二章反汇编难点分析反汇编帮助跟踪参数生成函数反汇编难点分析 首先就是上一章提到的&#xff0c;指令的顺序是会变的 假设某序号为1的指令为【I[I.length - 2] I[I.length - 2] I.pop();】 这个指令可能在下一次请求的时候&#xff0c;序号变…

C++ Reference: Standard C++ Library reference: Containers: map: map: end

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/end/ 公有成员函数 <map> std::map::end C98 iterator end(); const_iterator end() const; C11 iterator end() noexcept; const_iterator end() const noexcept;返回指向结束的iterator 返回一个指…

常用代码模板2——基础算法

构思算法&#xff1a;可以先想暴力解法&#xff0c;然后观察时间复杂度&#xff0c;如果超时&#xff0c;再考虑优化&#xff0c;优化的方向就是时间复杂度要下降&#xff0c;下表可以给出一些算法选择的参考&#xff1a; 暴力枚举 -> 枚举优化 -> 正解 数据范围时间复…

Qt扫盲-QTabWidget理论总结

QTabWidget理论总结1. 简述2. 用法流程3. 选项卡设置3. 页面信息3. 外观4. 扩展1. 简述 QTabWidget 提供一个选项卡栏和一个“页面区域”&#xff0c;用于显示与每个选项卡相关的页面。默认情况下&#xff0c;选项卡栏显示在页面区域上方&#xff0c;但可以使用不同的配置&…

智能合约简单介绍

本学期学习了区块链的课程&#xff0c;作业是对于智能合约学习后的报告&#xff1a; 1 智能合约简单了解 1.1智能合约是什么 智能合约是由事件驱动的、具有状态的、部署于可共享的分布式数据库上的计算机程序&#xff0c;多用IF-THEN语句。狭义来说&#xff0c;智能合约是设计…

函数式编程 | 图文详解 | 系统性学习 | 无知的我费曼笔记

无知的我正在复盘函数式编程 该笔记特点是 重新整理了涉及资料的一些语言描述、排版而使用了自己的描述对一些地方做了补充说明。比如解释专有名词、类比说明、对比说明、注意事项提升了总结归纳性。尽可能在每个知识点上都使用一句话 || 关键词概括更注重在实际上怎么应用提出…

70. 利用 ALV 实现增删改查系列之二:仅让 ALV 报表某一列允许被编辑

本系列前一篇文章 69. 利用 ALV 实现增删改查系列之一:让 ALV 报表进入可编辑状态,我们介绍了如何让 SAP ABAP ALV 报表进入可编辑状态。在该状态下,ALV 报表的每一行,每一列都可以被任意修改,如下图所示: 但是在实际的项目中,更常见的需求是,ALV 报表只允许部分列能够…

【Vue脚手架】总结笔记

脚手架文件结构 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue │ │…

Springboot 整合 ireporter 实践

背景 这段时间&#xff0c;在做项目时&#xff0c;设计到需要带参数的批量生成报告。尝试了很多方法&#xff0c;包括grafana等BI工具。虽然grafana这种BI工具可以在线查看&#xff0c;但是无法导出。甚至当想把报告整合邮件发送时&#xff0c;grafana就显得无能为力了。于是在…

Sql Server 占用内存高,不释放内存问题处理记录(腾讯电脑管家小火箭清内存)

问题&#xff1a; 本人仓库管理系统厂家&#xff0c;项目上反应生产线箱码不能上传到我们系统&#xff0c;我们的WMS软件退出后重新登录也一直登录失败&#xff0c;并且服务器上数据库占用内存过高&#xff0c;SSMS数据库连接不上。 好家伙SQL Server占用了34个G内存。 接口…

前端基础(十二)_overflow属性、clear属性、vertical-align属性

overflow属性 overflow的第一个属性值是x轴方向的属性&#xff0c;第二个值是y周方向的属性 <style>.box1 {width: 150px;height: 50px;等价于下面两个属性/* overflow: hidden auto; */overflow-x: hidden;overflow-y: auto;}</style>1、overflow-x 只包含水平方…

VS2019编译QT6源码

现在QT在线安装只有QT6.2以上的版本和QT5.15&#xff0c;其他版本就需要自己编译&#xff0c;本文讲解在vs2019环境下编译qt6.1.3源码。 1 编译准备 从清华大学镜像站&#xff0c;下载源码&#xff0c;地址如下&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/qt/archive/…