Collection线程不安全的举例

news2025/1/18 17:10:46

目录

  • 一、前言
  • 二、单线程环境下
  • 三、多线程环境
  • 四、解决方案
    • 方案一:Vector
    • 方案二:Collections.synchronized()
    • 方案三:采用JUC里面的方法
  • 五、HashSet线程不安全
  • 六、HashMap线程不安全

一、前言

1、当我们执行下面语句的时候,底层进行了什么操作

new ArrayList<Integer>();

底层创建了一个空的数组,伴随着初始值为10
当执行add方法后,如果超过了10,那么会进行扩容,扩容的大小为原值的一半,也就是5个,使用下列方法扩容

Arrays.copyOf(elementData, netCapacity)

二、单线程环境下

单线程环境的ArrayList是不会有问题的

public class ArrayListNotSafeDemo {
    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");

        for(String element : list) {
            System.out.println(element);
        }
    }
}

三、多线程环境

为什么ArrayList是线程不安全的?因为在进行写操作的时候,方法上为了保证并发性,是没有添加synchronized修饰,所以并发写的时候,就会出现问题
在这里插入图片描述
当我们同时启动30个线程去操作List的时候

public class TestServiceLoader{
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

这个时候出现了错误,也就是java.util.ConcurrentModificationException
在这里插入图片描述
这个异常是 并发修改的异常

四、解决方案

方案一:Vector

第一种方法,就是不用ArrayList这种不安全的List实现类,而采用Vector,线程安全的
关于Vector如何实现线程安全的,而是在方法上加了锁,即synchronized
在这里插入图片描述
这样就每次只能够一个线程进行操作,所以不会出现线程不安全的问题,但是因为加锁了,导致并发性基于下降

方案二:Collections.synchronized()

List<String> list = Collections.synchronizedList(new ArrayList<>());

采用Collections集合工具类,在ArrayList外面包装一层 同步 机制

方案三:采用JUC里面的方法

CopyOnWriteArrayList:写时复制,主要是一种读写分离的思想

写时复制,CopyOnWrite容器即写时复制的容器,往一个容器中添加元素的时候,不直接往当前容器Object[]添加,而是先将Object[]进行copy,复制出一个新的容器object[] newElements,然后新的容器Object[] newElements里添加原始,添加元素完后,在将原容器的引用指向新的容器 setArray(newElements);这样做的好处是可以对copyOnWrite容器进行并发的读 ,而不需要加锁,因为当前容器不需要添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器

就是写的时候,把ArrayList扩容一个出来,然后把值填写上去,在通知其他的线程,ArrayList的引用指向扩容后的

查看底层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();
        }
    }

首先需要加锁

final ReentrantLock lock = this.lock;
lock.lock();

然后在末尾扩容一个单位

Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);

然后在把扩容后的空间,填写上需要add的内容

newElements[len] = e;

最后把内容set到Array中

五、HashSet线程不安全

CopyOnWriteArraySet
底层还是使用CopyOnWriteArrayList进行实例化
在这里插入图片描述
HashSet底层结构
同理HashSet的底层结构就是HashMap
在这里插入图片描述
但是为什么我调用 HashSet.add()的方法,只需要传递一个元素,而HashMap是需要传递key-value键值对?
首先我们查看hashSet的add方法

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

我们能发现但我们调用add的时候,存储一个值进入map中,只是作为key进行存储,而value存储的是一个Object类型的常量,也就是说HashSet只关心key,而不关心value

六、HashMap线程不安全

同理HashMap在多线程环境下,也是不安全的

    public static void main(String[] args) {

        Map<String, String> map = new HashMap<>();

        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }

解决方法
1、使用Collections.synchronizedMap(new HashMap<>());
2、使用 ConcurrentHashMap

Map<String, String> map = new ConcurrentHashMap<>();

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

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

相关文章

项目注意总结

过了周四删 天山天池 游览路线 看抖音&#xff0c;没啥可避坑的&#xff0c;220的缆车 风景独好&#xff0c;看选择&#xff1b; 天山天池&#xff0c;又称天池国家地质公园&#xff0c;古称“瑶池”&#xff0c;位于昌吉州阜康市境内&#xff0c;博格达峰的北侧&#xff0c…

eBay 工程师:API 变革面临挑战,契约测试能否成为解决方案?

近年来&#xff0c;随着微服务架构的广泛采用&#xff0c;契约测试&#xff08;Contract Testing&#xff09;越来越受欢迎。在这篇文章中&#xff0c;我们将分享我们在 eBay 的契约测试的经验。 在微服务架构中&#xff0c;服务通常通过远程过程调用或异步消息进行整合。测试…

测试管理的能力和素质

测试管理是软件开发中至关重要的一环&#xff0c;测试管理员需要具备一系列的能力和素质来确保项目成功交付。以下是测试管理者需要具备的能力和素质&#xff1a; 1. 技术能力 测试管理员需要对软件测试技术有深入的了解&#xff0c;包括测试策略、测试计划、测试用例设计、测试…

OLED 液晶屏显示模块(0.96寸)

OLED模块例程 一、OLED 简介&#xff1a; OLED&#xff0c;即有机发光二极管&#xff08;Organic Light-Emitting Diode&#xff09;&#xff0c;又称为有机电激光显示&#xff08;Organic Electroluminesence Display, OELD&#xff09;。因为具备轻薄、省电等特性&#xff…

互联网用户之间如何传输大文件

互联网用户之间如何传输大文件&#xff1f; 现在的工作&#xff0c;基本上都离不开互联网&#xff0c;网络越来越发达&#xff0c;互联网传输大文件时常发生&#xff0c;但是有没有一款合适的大文件传输工具&#xff0c;很伤脑&#xff0c;下面整理了一些互联网用户之间如何传…

USB SS-PHY Tuning

1 USB 3.0 PIPE PHY 1.1 USB 3.0 PHY USB 3.0 PHY PIPE wrapper PCS SerDes 1.2 SS PHY电流源 CML电流源串联在NMOS管的Source中&#xff0c;电流是16 mA&#xff0c;所以差分电压摆幅是16 mA x (50 // 50) x 2 800 mV。 1.3 PIPE PHY数据线宽度 DWC_usb3_databook_2.50a.p…

涂鸦智能生活App SDK:全量级灵活定制,让你的App更具差异化

之前一期&#xff0c;我们介绍过涂鸦 OEM App 开发方案&#xff08;点击查看往期介绍&#xff09;&#xff0c;它集品牌 UI 自定义、服务、运营、商城营销于一体&#xff0c;无需代码&#xff0c;开发者点选拖拽即可快速配置想要的常用功能&#xff0c;最快 10 分钟即可完成一款…

【敬伟ps教程】历史工具、画笔、橡皮擦

文章目录 历史工具面板上的操作按历史记录选项历史记录画笔历史记录艺术画笔 画笔工具画笔基本操作画笔预设画笔面板 铅笔工具背景橡皮擦魔术橡皮擦 历史工具 窗口–历史记录 历史记录是从上到下是操作步骤&#xff0c;编辑时会有很多历史记录&#xff0c;点击下方删除按钮可删…

产线故障ar远程协助系统为运维提供可视化的画面

说起AR增强现实技术&#xff0c;其适为企业设计、生产、装配、销售和运维所有链条提供更优的解决方案&#xff0c;今天为您具体介绍AR远程专家协助技术应用工作制造中的好处。 1、设备、产线发生重大故障&#xff0c;需要厂家派人来现场&#xff0c;停工损失巨大; 2、借助手机进…

【PyQt】PyQt学习(三)QWidget介绍

概述 QWidget 类是所有 Qt GUI 界面类的基类&#xff0c;是 PyQt 程序中的最小元素&#xff0c;也就是所有可现实的控件的基类。一个继承自 QWidget 的类可以在屏幕上绘制自身&#xff0c;这是因为 QWidget 继承了 QPaintDevice 类&#xff0c;该类用于将控件绘制在屏幕上。每一…

leecode每日一题 1054 距离相等的条形码

题目描述 在一个仓库里&#xff0c;有一排条形码&#xff0c;其中第 i 个条形码为 barcodes[i]。请你重新排列这些条形码&#xff0c;使其中任意两个相邻的条形码不能相等。 你可以返回任何满足该要求的答案&#xff0c;此题保证存在答案。 示例 1&#xff1a; 输入&#xf…

JS逆向 -- 分析某站aid、cid、w_rid和sid的加密过程

接上节课内容 JS逆向 -- 分析某站buvid3和_uuid的加密过程 JS逆向 -- 分析某站b_lsid值加密过程 一、清除cookie信息&#xff0c;刷新网页&#xff0c;ctrlf搜索sid&#xff0c;这样找到的数据是在url里或者响应信息里面&#xff0c;全局搜索找到的一般都是在js里面的数据&a…

ChatGPT生成Excel统计公式——检查数据是否满足要求

背景需求 有一张表格如下&#xff0c;需要统计每个用户是否在第一到第三周中&#xff0c;每周发文数量都大于等于两篇&#xff0c;是的话给出Yes&#xff0c;否的话给出No 操作流程 给出描述&#xff0c;让ChatGPT生成对应的公式&#xff0c;条件如下&#xff1a; 在excel中…

【保护和自动控制 JDX-1000信号继电器 机械保持、电复归 JOSEF约瑟】

名称&#xff1a;信号继电器&#xff1b;型号&#xff1a;JDX-1000系列&#xff1b;品牌&#xff1a;JOSEF约瑟&#xff1b;额定电压&#xff1a;110、220VDC/AC&#xff1b;起动电流&#xff1a;3mA&#xff1b;稳定电流&#xff1a;2A&#xff1b;功率消耗&#xff1a;不大于…

TH2822D手持式 LCR数字电桥产品资料

TH2822D是一款手持式LCR数字电桥&#xff0c;可测量电容、电感和电阻&#xff0c;具有高精度、高灵敏度、低功耗和易于携带等特点。TH2822D适用于生产、现场维修和科研等多个领域。 TH2822D手持式LCR数字电桥的主要特点如下&#xff1a;1. 标准源四终点测量方法&#xff0c;准…

【优秀!44个HCIA-Datacom知识点总结】

1、IPV4地址的组成部分&#xff1f;IP地址长度&#xff1f;表达形式&#xff1f;如何区分网络位和主机位&#xff1f; 组成部分&#xff1a;网络位主机位 IP地址长度&#xff1a;32bit 表达形式&#xff1a;点分十进制 区分&#xff1a;子网掩码区分&#xff0c;为1是网络位&am…

以云原生推动代际跃升,2023通明湖论坛云原生分论坛召开

5月12日&#xff0c;由神州数码主办&#xff0c;北京经开区国家信创园、中关村云计算产业联盟协办的2023通明湖论坛-云原生分论坛在京召开。本次论坛&#xff0c;以“抓住云原生机遇&#xff0c;推动我国信息基础设施技术代际跃升”为主题&#xff0c;聚焦以云原生为核心引领的…

vue2和elementUI 打造落日余晖登录页和滑块校验

文章目录 前言1 项目搭建2 依赖引入3 项目调整①vue-router② App.vue③ main.js 4 写登录页5 写滑块校验6 源码下载7 问题解决①项目一直报错② 背景图存在白边 前言 标题很夸张&#xff0c;实则是AI的功能&#xff0c;今天咱也搞一个登录页&#xff0c;其实满简单的一个东东…

Gigabayte-Z87-DS3H i3 4130电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。&#xff08;下载请直接百度黑果魏叔&#xff09; 硬件型号驱动情况 主板Gigabayte-Z87-DS3H 处理器英特尔酷睿i3 4130 Haswell已驱动 内存4x4GB DDR3/1600Mhz金士顿已驱动 硬盘SSD 480GB PNY CS900已驱动 显卡英特尔高…

想学透OSPF,先搞懂这6个技术点再说

大家好&#xff0c;我是老杨。 OSPF&#xff0c;这玩意儿作为目前主流的IGP协议&#xff0c;主要是为了解决RIP的三大问题而出现的。 应用面非常广&#xff0c;认可度也高&#xff0c;毕竟的确是好用的。 也有很多正在学习的小友想找我讲讲&#xff0c;OSPF该怎么学。 基础的…