【集合】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,一经查实,立即删除!

相关文章

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…

微信小程序---分包

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

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

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

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…

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

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

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

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

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

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

【电商】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;今天一起来讨论一下&…

Vue和React的运行时,校验引入包的上下文差异

背景 系统使用 webpack 5 模块联邦实现微前端&#xff0c;有关如何实现跨应用的代码共享&#xff0c;可参考 如何优雅的实现跨应用的代码共享 里的第三大点。 总之&#xff0c;这里是其他应用使用了某个应用共享出来的reg文件&#xff0c;引入方式为&#xff1a; import REG …

Dbeaver如何连接Oceanbase?

Dbeaver & Oceanbase 一、新增驱动二、连接数据库 一、新增驱动 1、新建驱动 点击数据库 -> 驱动管理器 -> 新建 2、设置驱动 驱动名称可随意填写注意驱动类型要是Generichost:port填写实际的host和port 库中新增下载的oceanbase驱动jar包 二、连接数据库 1、找…

ECMAScript 6 - 通过Promise输出题理解Promise

1 题目(1) 题目背景&#xff1a;分享洛千陨 珍藏题 const p1 () > (new Promise((resolve, reject) > {console.log(1);let p2 new Promise((resolve, reject) > {console.log(2);const timeOut1 setTimeout(() > {console.log(3);resolve(4);}, 0)resolve(5)…

【前端框架React】原理

React设计思想 1.原生JS React相比于vue来说更接近原生JS&#xff0c;因为在react内部&#xff0c;jsx模板经babel转化后是一个对象&#xff0c;所有的操作都是基于这个对象和其对应的fiber结构来操作的&#xff0c;而vue.js通过编译将templete模板转换成渲染函数(render),执…

工具系列:TensorFlow决策森林_(3)使用dtreeviz可视化

文章目录 介绍设置安装 TF-DF 和 dtreeviz导入库 可视化分类树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随机森林分类器显示决策树检查叶节点统计信息决策树如何对实例进行分类特征空间划分 可视化回归树加载、清洗和准备数据分割训练/测试集并训练模型训练一个随…