【集合】Vector与CopyOnWriteArrayList

前言:

        此篇博客着重于:在多线程并发执行读、写操作的场景下Vector集合CopyOnWriteArrayList集合是否能保证线程安全?它们是通过什么方式保证线程安全的?

Vector:

        (1)add(E e)方法实现

public synchronized boolean add(E e) {//modCount:修改表结构的次数(增、删、改等操作都算修改了表结构)modCount++;//确保数组容量没有达到上限,达到上限则扩容ensureCapacityHelper(elementCount + 1);//将元素添加到Object数组elementData[elementCount++] = e;//返回指向结果return true;}private void ensureCapacityHelper(int minCapacity) {// overflow-conscious code// 如果动态数组容量达到了上限if (minCapacity - elementData.length > 0)//扩容grow(minCapacity);}private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);}

        (2)get(int index)方法实现

public synchronized E get(int index) {//如果索引越界,则直接抛出异常if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);//否则通过索引返回对应元素return elementData(index);}E elementData(int index) {//通过索引获取Object数组中的元素//将Object对象强转成泛型E返回return (E) elementData[index];}

        总结

        无论是add(E e)方法,还是get(int index)方法,方法声明上都有synchronized关键字,这意味着每次读、写操作都会对当前Vector对象上锁,保证同一时间并发的多个读、写线程是串行执行的,以此来确保多线程并发读、写时的线程安全。

        图解

为什么并发读、写场景下,不上锁会有线程安全问题呢?

以get(int index)(读操作)、remove(int index)(写操作)这两个方法为切入点分析

        get(int index)方法可以分为两步1、判断索引是否越界;2、返回索引对应的元素。

        remove(int index)方法也可以分为两步1、从数组中移除指定数据;2、更新数组元素数量。

public synchronized E remove(int index) {modCount++;if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);E oldValue = elementData(index);int numMoved = elementCount - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--elementCount] = null; // Let gc do its workreturn oldValue;}

        此时有一个get线程和一个remove线程同时来操作Vector对象,操作动态数组的最后一个元素,由于没有加锁,任何执行顺序都是有可能的。假设有如下图所示的执行顺序

        我们预期的结果是get线程会报数组越界异常,但结果却是返回了一个null值,与我们想要的结果不符。写线程修改了Vector集合的结构后,我们期望读线程能感知到表结构的改变,所以线程安全问题实质上是数据一致性问题。

CopyOnWriteArrayList:

        我们分析了Vector集合的add、get方法,知道了Vector集合多线程并发场景下,保证线程安全的原理:读、写操作都会对当前Vector集合对象上synchronized锁。但其实多线程并发执行读操作的场景是不会有线程安全问题的,这时候我们就希望有一个集合类,它能将读、写操作分离,只让写线程串行执行,而读线程可以并行执行,这个集合类就是:CopyOnWriteArrayList

        如何实现读、写分离?

        让我们来看看add(E e)方法实现

public boolean add(E e) {final ReentrantLock lock = this.lock;//获取锁对象lock.lock();try {//获取存储元素的Object数组Object[] elements = getArray();//获取Object数组长度int len = elements.length;//拷贝旧Object数组得到一个新的Object数组//新数组长度比旧数组长度多1Object[] newElements = Arrays.copyOf(elements, len + 1);//将元素插入新的Object数组newElements[len] = e;//使用新数组覆盖旧数组setArray(newElements);//返回return true;} finally {//finally块释放锁,避免死锁lock.unlock();}}

        get(int index)方法实现

public E get(int index) {return get(getArray(), index);}private E get(Object[] a, int index) {return (E) a[index];}//获取当前Object数组
final Object[] getArray() {//array:成员变量,是集合类底层存储元素的Object数组return array;}

总结:       

         1、多个写线程并发访问CopyOnWriteArrayList集合对象时,只有一个写线程能获取到ReentrantLock锁,所有写线程串行执行。

        2、add插入逻辑:获取旧数组及旧数组长度;基于旧数组拷贝出一个新数组,新数组长度为旧数组长度+1;将元素插入到新数组中,并用新数组覆盖掉旧数组。

        3、get方法逻辑:无需上锁,使用getArray()方法获取当前的Object数组,并通过索引查找对应元素即可。

        基于CopyOnWriteArrayList的特点我们不难发现,这种集合对象只适用于读多写少的场景,如果写线程远多于读线程,写线程串行执行的同时还要执行耗时的拷贝操作,性能较低。

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

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

相关文章

Linux系统下修改环境变量及生效方法

1.修改环境变量 &#xff08;1&#xff09;打开终端&#xff0c;输入以下命令后回车&#xff1a; vim ~/.cshrc &#xff08;2&#xff09;将所需的环境变量添加进去&#xff0c;按“Esc”退出&#xff0c;再按shiftZZ&#xff0c;使其保存 2.执行source ~/.cshrc使其生效即…

Text to image论文精读 TISE (Text-to-Image Synthesis Evaluation):用于文本到图像合成的评估度量工具包

TISE (Text-to-Image Synthesis Evaluation)是一款用于评估文本生成图像的Python评估工具箱。文章由Tan M. Dinh, Rang Nguyen, and Binh-Son Hua等人发表。 其以统一的方式促进、倡导公平的评估度量&#xff0c;并为未来的文本到图像综合研究提供可重复的结果。 文章链接&am…

centos7.9中离线安装nginx开启ssl,arm架构

一、首先需要去国内相关镜像库下载相关依赖rpm&#xff1a; http://mirrors.bfsu.edu.cn/centos-altarch/7.9.2009/os/aarch64/ http://mirror.nju.edu.cn/centos-altarch/7.9.2009/os/aarch64/ http://mirrors.tuna.tsinghua.edu.cn/centos-altarch/7.9.2009/os/aarch64/ htt…

电子企业数字工厂管理系统有哪些实施难点

随着科技的快速发展&#xff0c;数字化转型已经成为企业提升竞争力、优化生产流程的必经之路。在电子企业中&#xff0c;数字工厂管理系统的实施尤为关键&#xff0c;它能够助力企业实现高效、精准的生产管理。然而&#xff0c;在实际操作过程中&#xff0c;实施数字工厂管理系…

linux ARM64 异常

linux 的系统调用是通过指令陷入不同异常级别实现的。arm64 架构的 cpu 的异常级别结构如下&#xff1a; 在上图中&#xff0c;用户层运行在 EL0 也就是异常级别 0&#xff0c;Linux 内核运行在 EL1 也就是异常级别 1&#xff0c;安全可信操 作系统运行在异常级别 2&#xff1a…

(四) ClickHouse 中使用 `MaterializedMySQL` 引擎单独同步 MySQL 数据库中的特定表(例如 `aaa` 和 `bbb`)

要在 ClickHouse 中使用 MaterializedMySQL 引擎单独同步 MySQL 数据库中的特定表&#xff08;例如 aaa 和 bbb&#xff09;&#xff0c;您可以使用 TABLE OVERRIDE 功能。这个功能允许您指定要同步的特定表&#xff0c;同时忽略其他表。以下是步骤说明&#xff1a; 1. 启用 M…

微信小程序---分包

概念&#xff1a;分包就是把一个完整的小程序项目&#xff0c;按照需求划分为不同的子包&#xff0c;在构建时打包成不同的分包&#xff0c;用户在使用时按需进行加载。 分包的优点&#xff1a;可以优化小程序首次启动的下载时间&#xff0c;在多团队共同开发时可以更好的解耦…

[2023-年度总结]凡是过往,皆为序章

原创/朱季谦 2023年12月初&#xff0c;傍晚&#xff0c;在深圳的小南山看了一场落日。 那晚我们坐在山顶的草地上&#xff0c;拍下了这张照片——仿佛在秋天的枝头上&#xff0c;结出一颗红透的夕阳。 这一天很快就会随着夜幕的降临&#xff0c;化作记忆的碎片&#xff0c;然…

calc()

需要注意的是&#xff0c;运算符前后都需要保留一个空格&#xff0c;例如&#xff1a;width: calc(100% - 10px)&#xff1b;任何长度值都可以使用calc()函数进行计算&#xff1b;calc()函数支持 "", "-", "*", "/" 运算&#xff1b;c…

ComfyUI如何中文汉化

comfyui中文地址如下&#xff1a; https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translationhttps://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translation如何安装&#xff1f; 1. git安装 进入项目目录下的custom_nodes目录下&#xff0c;然后进入控制台&#xff0c;运…

Geotrust与QuickSSL证书

随着互联网的发展&#xff0c;SSL证书已经成为了保护网站数据传输安全的重要手段。然而&#xff0c;一些SSL证书申请流程繁琐&#xff0c;需要提供各种证明文件和等待审核&#xff0c;这对于许多小型企业或个人站长来说是一个很大的困扰。QuickSSL是Geotrust旗下的子品牌之一&a…

飞天使-k8s知识点7-kubernetes升级

文章目录 验证新版本有没有问题需要安装的版本微微 1.20.6.0kubeadm upgrade plan 验证新版本有没有问题 查看可用版本的包 现有的状态 查看版本 yum list kubeadm --showduplicates |grep 1.20 yum list kubelet --showduplicates |grep 1.20 yum list kubectl --showduplic…

什么是CPA、CPS、CPM、CPT、CPC

网络营销中的几个常见基本术语&#xff1a;CPA、CPS、CPM、CPT、CPC 他们的英文全称与基本含义分别是&#xff1a; CPA(Cost Per Action) 每行动成本。CPA是一种按广告投放实际效果计价方式的广告&#xff0c;即按回应的有效问卷或注册来计费&#xff0c;而不限广告投放量。电…

P1016 [NOIP1999 提高组] 旅行家的预算

网址如下&#xff1a; P1016 [NOIP1999 提高组] 旅行家的预算 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 考前练练手 一道 普及/提高 难度的题 秒了 想到以前高中的时候被普及难度的题按在地上摩擦&#xff0c;现在能秒洛谷普及难度的题&#xff0c;有点泪目 代码如下…

记账导出excel表格,用表格导出账目数据

我们每天都在跟金钱打交道,记账则是更好地管理自己财务的一种方式&#xff0c;传统记账不仅繁琐&#xff0c;还容易出错。那么&#xff0c;有没有简单、高效的记账方式呢&#xff1f;答案是肯定的&#xff01;今天&#xff0c;我们就向大家推荐一款全新的记账软件——晨曦记账本…

电子公章软件,怎么实现批量自动盖章?

在商务合作中&#xff0c;企业电子公章软件在提高办公效率、确保文件的法律效力方面发挥着关键作用。微签是国内电子公章软件领域的拓荒者之一&#xff0c;有19年的电子签研发应用经验&#xff0c;专注于审批场景中的安全签章。 今天&#xff0c;微签给大家带来了详细的“批量…

【Kafka每日一问】kafka如何扩容broker,对于新增加的broker什么时候会将分区复制到新的broker上?

在Kafka中&#xff0c;扩容Broker&#xff08;消息存储节点&#xff09;是一种常见的操作&#xff0c;用以提升集群的存储容量和提高整体吞吐量。当你需要扩容Kafka集群时&#xff0c;通常会添加新的Broker节点。以下是扩容Kafka Broker的基本步骤&#xff1a; 1. 准备新Broke…

【电商】AI模特 高清放大

目录 实战一&#xff1a;模特人偶 实战二&#xff1a;3D OPEN POSE 生成 模特 高清放大&#xff08;可开启ADetailer&#xff09; 实战三&#xff1a;半身模特 随机生成 高清放大&#xff08;可开启ADetailer&#xff09; 实战四&#xff1a;人偶生成模特图 实战一&#x…

文献速递:生成对抗网络医学影像中的应用——3DGAUnet:一种带有基于3D U-Net的生成器的3D生成对抗网络

文献速递&#xff1a;生成对抗网络医学影像中的应用——3DGAUnet&#xff1a;一种带有基于3D U-Net的生成器的3D生成对抗网络 给大家分享文献的主题是生成对抗网络&#xff08;Generative adversarial networks, GANs&#xff09;在医学影像中的应用。文献的研究内容包括同模态…

线上服务有哪些稳定性指标?

在分布式高可用设计中&#xff0c;系统监控非常重要&#xff0c;系统监控做好了&#xff0c;可以提前对异常情况进行报警&#xff0c;避免很多线上故障的产生。系统监控做得好不好&#xff0c;也是评价一家互联网公司基础建设水平的重要标准&#xff0c;今天一起来讨论一下&…