探索ArrayList的线程不安全性

news2024/11/15 9:29:36

文章目录

    • 概要
    • 示例代码
    • 原因
    • 解决
      • 用 synchronized 保证安全添加元素
      • 其他方法
    • 总结

概要

要测试ArrayList的线程不安全性,可以创建多个线程同时对 ArrayList 进行修改操作(如添加、删除元素),并观察是否会引发异常或数据不一致的问题

示例代码

    public static void main(String[] args) throws InterruptedException {
        List<Integer> list = new ArrayList<>(6000);
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 3000; i++) {
                list.add(i);
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 3000; i++) {
                list.add(-i);
            }
        });

        thread1.start();
        thread2.start();

        thread1.join(); // 主线程等待子线程执行结束  主线程才继续执行
        thread2.join();

        System.out.println("数组大小:" + list.size());
    }

执行结果:
在这里插入图片描述

每次结果都不一样,正确的数量因该是2个线程分别添加元素数量总和

原因

在并发环境中,当多个线程同时对 ArrayList 进行操作时,它们之间的竞争可能会导致数据丢失。例如,当多个线程同时调用 add 方法时,可能会出现数据覆盖:如果多个线程同时试图在 ArrayList 中添加元素,它们可能会在同一位置进行写操作,导致之前写入的元素被覆盖。

ArrayList 的 add 操作并不是原子的。在多线程环境下,如果两个线程同时执行 add 操作,它们可能会同时访问和修改 ArrayList 的内部数据结构。这种缺乏原子性的操作会导致竞态条件和数据丢失。

解决

用 synchronized 保证安全添加元素

public synchronized static void addNum(List<Integer> list, int num) {
    list.add(num);
}

public static void main(String[] args) throws InterruptedException {
    List<Integer> list = new ArrayList<>(6000);
    
    Thread thread1 = new Thread(() -> {
        for (int i = 0; i < 3000; i++) {
            addNum(list, i);
        }
    });

    Thread thread2 = new Thread(() -> {
        for (int i = 0; i < 3000; i++) {
            addNum(list, -i);
        }
    });

    thread1.start();
    thread2.start();

    thread1.join();
    thread2.join();

    System.out.println("数组大小: " + list.size());
}

执行结果:
在这里插入图片描述

其他方法

  • Collections.synchronizedList:使用 Collections.synchronizedList(new ArrayList<>()) 来包装 ArrayList,以确保对集合的操作是线程安全的。
  • CopyOnWriteArrayList:使用 CopyOnWriteArrayList,这是一个线程安全的 List 实现,适用于读多写少的场景。
    public static void main(String[] args) throws InterruptedException {
        List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>(6000));
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 3000; i++) {
                list.add(i);
            }
        });
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 3000; i++) {
                list.add(-i);
            }
        });
        thread1.start();
        thread2.start();

        thread1.join(); // 主线程等待子线程执行结束  主线程才继续执行
        thread2.join();

        System.out.println("数组大小:" + list.size());
    }

总结

HahsMap TreeMap 都不是线程安全的,当然 HashSet 由 HashMap 实现,所以 HashSet 线程不安全; TreeSet 由 TreeMap 实现,所以 HashSet 线程不安全。为了解决这个问题,可以使用线程安全的替代品,例如通过 Collections.synchronizedSet() 来包装一个 Set,确保其线程安全。

Collections工具类中的替代品
在这里插入图片描述
写时复制
CopyOnWrite 是一种并发编程策略,常用于实现线程安全的集合类。它的核心思想是在进行写操作时,复制底层数据结构的一个副本,并在新副本上执行修改操作,旧的副本仍然保持不变,供当前正在进行的读操作使用。这种策略适用于读操作频繁、写操作较少的场景。
在这里插入图片描述


❤觉得有用的可以留个关注~~❤

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

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

相关文章

Typescript实现react-redux的useSelector和useDispatch的状态定义

背景&#xff1a;react中使用typescript,在引入redux之后很多状态定义有问题&#xff0c;记录下来&#xff08;文章记录学习react-redux过程中的踩坑&#xff09;。 1.useSelector时&#xff0c;state语法报错&#xff0c;类型为unknown,如下图 我的store状态设置的很简单&am…

Luminar Neo for Mac智能图像处理软件【操作简单,轻松上手】

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试安装完成&#xff01;&#xff01;&#xff01; 效果 一、下载软件 下载软件…

【机器学习】LSTM(长短期记忆网络)详解

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 LSTM(长短期记忆网络)详解LSTM的基本思想LSTM的前向传播过程LSTM在实际任务中的…

mysql高级知识之集群

一、安装 源码编译MySQL,若需要MySQLtar包可私信我 #创建数据目录 mkdir /data/mysql -p#安装相关依赖 yum install libtirpc-devel-0.2.4-0.16.el7.x86_64.rpm yum install cmake gcc-c++ openssl-devel ncurses-devel.x86_64 libtirpc-devel-1.3.3-8.el9_4.x86_64.rpm rpcgen…

C++入门day3-面向对象编程(中)

前言&#xff1a;C入门day2-面向对象编程&#xff08;上&#xff09;-CSDN博客 运算符重载 我们接触过函数重载&#xff0c;就是同名的函数有不同的功能。那么运算符重载&#xff0c;顾名思义也是赋予运算符其他的功能。在这里&#xff0c;我个人以为&#xff0c;运算符就是特…

C/C++语言基础--函数基础(函数定义、调用、生命周期、递归)

本专栏目的 更新C/C的基础语法&#xff0c;包括C的一些新特性 前言 函数是语言的基本组成部分&#xff0c;也是面向对象编程的基石&#xff0c;他体现了封装的思想&#xff0c;代码的复用的功能。欢迎点赞 收藏 关注&#xff0c;本人将会持续更新 文章目录 函数什么是函数&am…

彩漩科技亮相第一届人工智能教育应用论坛,荣获AI教育科技产品TOP30奖项

近日&#xff0c;由中国教育发展战略学会人工智能与机器人教育专业委员会指导&#xff0c;北京教育信息化产业联盟主办的第一届人工智能教育应用论坛暨 AI 教育科技成果展在北京隆重举办。本次活动以“ AI 强校大时代 —— 用新质生产力打造金钥匙强校”为主题&#xff0c;汇聚…

vector 常见函数

目录 一.vector 构造函数 二 . Iterators 迭代器&#xff08;random access iterator&#xff09; 三.Capacity: 空间 3.1 resize 3.2 reserve 四.Element access: 元素访问 方式 4.1 operator[] 类似于数组的 [] 4.2 front 和back 五.Modifiers: 六.vector 的 二…

数据结构(单向链表)

单向链表代码 #ifndef _LINK_H_#define _LINK_H_typedef int DataType;typedef struct node {DataType data;struct node *pnext; }Link_Node_t;typedef struct link {Link_Node_t *phead;int clen; }Link_t;extern Link_t *link_creat(); extern int push_link_head(Link_t *…

智慧公厕技术应用、系统架构、应用功能有哪些?@卓振思众

智慧公厕的标准涵盖了多个方面&#xff0c;包括技术应用、系统架构、应用功能以及环保节能等。以下是【卓振思众】整理的一些标准要点&#xff1a; 技术应用‌物联网技术‌&#xff1a;通过无线传感器、监控设备等实时采集公厕内部环境数据。‌大数据与云计算‌&#xff1a;对数…

2157. 优秀的拆分(power)

代码 #include<bits/stdc.h> using namespace std; int a[10001]; int main() {int n,t1,k0;bool flagfalse;cin>>n;if(n%21) {cout<<-1;return 0;}while(n>0){if(n%21){k;a[k]t; }nn/2;tt*2;}if(k>1) {flagtrue;for(int ik;i>1;i--)cout<&l…

lit-llama代码解析

https://github.com/Lightning-AI/lit-llama/blob/main/README.md 下载的时候会报错误&#xff0c;因为网不行&#xff0c;一种方法就是多次尝试&#xff0c;另一种方法是终端连上代理下载 pycharm连接hugging face等网站_hugging face怎么连接-CSDN博客 根据指引下载权重 下…

springboot,maven多模块开发,子模块获取不到父模块添加的依赖,有多个root模块问题解决

错误示范 我以为放进去然后重载一下就是子模块了 导致后续在外层加的依赖&#xff0c;其article都接收不到 解决方案 需要在父模块的modules注册子模块 修改前后对比 此时子模块也能获取父模块的依赖

DDD设计方法-2-聚合、实体、值对象

前情提要&#xff1a;一共包含 如下六篇文章&#xff08;篇幅精简&#xff0c;快速入门&#xff09; 1、初识DDD 2、聚合、实体、值对象 3、仓储&#xff0c;封装持久化数据 4、端口和适配器 5、领域事件 6、领域服务&#xff0c;实现约定 DDD设计方法-2-聚合、实体、值对象&a…

基于mspm0g3507的智能送药小车(21年电赛f题,openmv寻迹,k210数字识别,并行pid调制)项目实验报告

2024年全国大学生电子设计竞赛&#xff08;TI杯&#xff09; 2024年7月17日 摘要&#xff1a;本项目由微处理器MSPM0G3507&#xff0c;编码器电机驱动&#xff0c;OPENMV、K210视觉处理单元&#xff0c;红外药品检测单元&#xff0c;ZIGBEE无限透传单元&#xff0c;OLED显示&am…

Docker数据卷和Dockerfile

1、什么是Docker数据卷 前言&#xff1a; 在下载的镜像中&#xff0c;我们不能够去改变它内部的一些配置&#xff0c;因为docker的镜像文件是已经配置好的&#xff0c;无法改变&#xff0c;我们只能改变镜像启动后的容器里面的内容&#xff0c;但是又因为&#xff0c;容器本来…

Java框架第四课(对Spring的补充Spring web)

目录 一.Spring web的认识 (1)Spring Web概念 (2)Spring web的特点 (3)Springweb运行的流程 (4)Springweb运行的流程图 二.搭建Spring web 三.自定义处理器类搭建 (1)处理器类配置 (2)处理器类接受请求 (3)获得请求数据 四.拦截器 (1)关于拦截器&#xff1a; (2)拦截器的…

【VMware】麒麟系统网络连接配置

在VMware配置页面点击编辑&#xff0c;进入虚拟网络编辑器将默认的 VMnet0删除&#xff0c;新建网络&#xff0c;设置桥接模式为Intel 打开主机cmd,查看主机IP地址&#xff0c;获取子网掩码&#xff0c;默认网关及DNS服务器 4.在主机寻找可用IP地址&#xff0c;ping不通的为未…

探秘发酵过程:酵母菌如何为白酒赋予不同风味?

在白酒酿造的神秘世界里&#xff0c;发酵过程如同一位隐形的艺术家&#xff0c;用其不同的笔触为白酒勾勒出千变万化的风味。而在这背后&#xff0c;酵母菌作为发酵的主角&#xff0c;发挥着至关重要的作用。今天&#xff0c;就让我们一起探秘发酵过程&#xff0c;了解酵母菌如…

shell 学习笔记:变量、字符串、注释

目录 1. 变量 1.1 定义使用变量 1.2 变量命名规则 1.3 只读变量 1.4 删除变量 1.5 变量类型 1.5.1 字符串变量 1.5.2 整数变量 1.5.3 数组变量 1.5.3.1 整数索引数组 1.5.3.2 关联数组 1.4 环境变量 1.5 特殊变量 2. 字符串 2.1 单引号字符串 2.2 双引…