【集合】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.rhkb.cn/news/225067.html

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

相关文章

Android笔记(二十一):Room组件实现Android应用的持久化处理

一、Room组件概述 Room是Android JetPack架构组件之一&#xff0c;是一个持久处理的库。Room提供了在SQLite数据库上提供抽象层&#xff0c;使之实现数据访问。 &#xff08;1&#xff09;实体类&#xff08;Entity&#xff09;&#xff1a;映射并封装了数据库对应的数据表中…

【力扣】199.二叉树的右视图

看到这个题目的一瞬间&#xff0c;我想递归&#xff0c;必须用递归。最近被递归折磨的有点狠&#xff0c;但是我感觉我快要打败它了&#xff0c;就是现在稍稍有点处于劣势。不过没关系&#xff0c;来日方长不是。 法一&#xff1a;递归 题解&#xff1a; 之前想的就是先递归&…

漏洞复现-泛微OA xmlrpcServlet接口任意文件读取漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

Vue 封装echarts柱状图(Bar)组件

目的&#xff1a;减少重复代码&#xff0c;便于维护 显示效果 组件代码 <template><div class"ldw-data-content-box"><div class"ldw-chilren-box"><div class"title" v-if"title">{{ title }}</div>…

聊聊CLI:一个比NPS更全面、客观的体验指标

说起NPS&#xff08;Net Promoter Score&#xff0c;净推荐值&#xff09;大家一定不会感到陌生&#xff0c;它被誉为客户体验管理&#xff08;CEM&#xff09;领域的黄金指标&#xff0c;以“衡量客户忠诚度”而受到大家的认可和追捧。 然而&#xff0c;随着时间的推移和各行业…

Day72力扣打卡

打卡记录 参加考试的最大学生数&#xff08;压缩状态DP&#xff09; 链接 class Solution:def maxStudents(self, seats: List[List[str]]) -> int:m, n len(seats), len(seats[0])# a[i] 是第 i 排可用椅子的下标集合a [sum((c .) << j for j, c in enumerate(s…

C++学习实践(一)高频面试问题总结(附详细答案)

文章目录 一、基础常见面试题1、数组和链表区别2、深拷贝和浅拷贝相关问题的区别3、a和a区别4、c内存模型5、四种强制转换和应用场景 二、指针相关1、指针和引用的区别2、函数指针和指针函数3、传指针、引用和值4、常量指针和指针常量5、野指针6、智能指针的用法 三、关键字作用…

基于5G智能网关的智慧塔吊监测方案

塔吊是建筑施工中必不可少的设施&#xff0c;由于塔吊工作重心高、起重载荷大、人工视距/视角受限等因素&#xff0c;也使得塔吊在工作过程中着较多的危险因素。对此&#xff0c;可以部署基于工业5G智能网关搭建智慧塔吊安全监测系统&#xff0c;实现对塔吊运行的全局精细监测感…

web3风险投资公司之Electric Capital

文章目录 什么是 Electric CapitalElectric团队 Electric Capital 开发者报告参考 什么是 Electric Capital 官网&#xff1a;https://www.electriccapital.com/ 官方github&#xff1a;https://github.com/electric-capital Electric Capital 是一家投资于加密货币、区块链企…

这一次,我准备了 20节 PyTorch 中文课程

对于刚接触深度学习的小白来说&#xff0c;PyTorch 是必会的框架。 只是&#xff0c;很多小伙伴还没来得及开启学习之路&#xff0c;一个最重要的问题就摆在了面前&#xff1a; PyTorch&#xff0c;该怎么学呢&#xff1f; 很多同学会自己在网上找资料&#xff0c;不仅耗费时间…

NET中使用SQLSugar操作sqlserver数据库

目录 一、SqlSugar是什么&#xff1f; 二、迁移和建表 1.建立实体 2.创建上下文类 3.在Program中添加SqlSugar服务 4.在控制器中注入上下文类 三、简单实现CURD功能 总结 一、SqlSugar是什么&#xff1f; SqlSugar是一款老牌 .NET 开源ORM框架。 主要特点&#xff1a…

智能优化算法应用:基于指数分布算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于指数分布算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于指数分布算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.指数分布算法4.实验参数设定5.算法结果6.…

二叉树进阶题目(超详解)

文章目录 前言根据二叉树创建字符串题目分析写代码 二叉树的层序遍历题目分析 写代码二叉树的层序遍历II题目分析写代码 二叉树的最近公共祖先题目分析写代码时间复杂度 优化思路优化的代码 二叉搜索树与双向链表题目分析写代码 从前序与中序遍历序列构造二叉树题目分析写代码从…

5G边缘计算:解密边缘计算的魔力

引言 你是否曾想过&#xff0c;网络可以更贴心、更智能地为我们提供服务&#xff1f;5G边缘计算就像是网络的小助手&#xff0c;时刻待命在你身边&#xff0c;让数字生活变得更加便捷。 什么是5G边缘计算&#xff1f; 想象一下&#xff0c;边缘计算就像是在离你最近的一层“云…

华为设备VRP系统管理

为了满足企业业务对网络的需求&#xff0c;网络设备中的系统文件需要不断进行升级。另外&#xff0c;网络设备中的配置文件也需要时常进行备份&#xff0c;以防设备故障或其他灾害给业务带来损害。在升级和备份系统文件或配置文件时&#xff0c;经常会使用FTP和TFTP来传输文件。…

git命令和docker命令

1、git git是分布式的版本控制工具 git可以通过本地仓库管理文件的历史版本记录 # 本地仓库操作的命令 # 初始化本地库 git init # 添加文件到暂存区 git add . git checkout 暂存区要撤销的文件名称 # 提交暂存区文件 git commit -m 注释# 版本穿梭 # 查看提交记录 git log…

零基础学Java第一天

1.什么是Java Java是一门编程语言 思考问题&#xff1a; 人和人沟通? 中文 英文 人和计算机沟通&#xff1f; 计算机语言&#xff1a; C C C# php python 2. Java诞生 前身叫Oak&#xff08;橡树&#xff09; 目前最流行的版本还是JDK8 3.Java三大平台体系 JavaSE&#xff08…

JSON在Java中的使用

目录 第一章、快速了解JSON1.1&#xff09;JSON是什么1.2&#xff09;json的语法格式①键值对、字符串、数字、布尔值、数组、对象②嵌套的格式 1.3&#xff09;为什么使用JSON 第二章、发送和接收JSON格式数据2.1&#xff09;postman发送JSON格式数据2.2&#xff09;Java后端接…

单片机通用项目开源电路,源码

1.基础部分 等… 2.硬件应用 555芯片的应用 电路&#xff1a; 代码 /*************** writer:shopping.w ******************/ #include <reg52.h> #define uint unsigned int #define uchar unsigned charsbit Signal P1^0; sbit BEEP P3^7;void Delay(uint …

计算机网络简述

前言 计算机网路是一个很庞大的话题。在此我仅对其基础概述以及简单应用进行陈述。后续或有补充以形成完善的计算机网络知识体系。 一.计算机网络的定义 根据百度词条的描述&#xff0c;计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过…