ArryList线程安全问题以及解决方案

news2024/11/20 11:32:19

arrayList是一个线程不安全的集合,在多线程情况下可能会引起数据不一致、数组越界等问题。下面具体列一下多线程情况下ArrayList会出现什么错误.

1.java.util.ConcurrentModificationException

 ConcurrentModificationException 中文意思就是并发修改异常,存在于并发使用 Iterator 时出现的时候.

在多线程的情况下,一个线程在使用Iterator进行遍历,另一个线程往集合里面新增了一条数据,就有可能会出现这个错误.

原因:ArrayList中存放了一个属性modCount记录了集合被修改的次数,在创建迭代器(Iterator)时会将modCount赋值到迭代器的expectedModCount属性中,迭代器调用next()方法时判断modCoun是否等于expectedModCount,如果不等于则抛出ConcurrentModificationException异常。

迭代器next方法源码:

public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

判断的方法是:checkForComodification

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

可以看出checkForComodification方法校验了两个属性是否相等,不相等会抛出异常。

多线程情况下出现创建完迭代器后,其他线程往集合里面添加了数据modCount加1,导致modCount与expectedModCount不相等,导致报错。

2.出现NULL问题和元素值覆盖

多线程情况下,会发现调用add方法没有传null的情况,但是输出集合内容时发现存在null值。

ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 300; i++) {
            new Thread(() -> {
                if (list.isEmpty()) {
                    list.add(UUID.randomUUID().toString().substring(0, 8));
                    System.out.println(list);
                    list.iterator();

                }
            }, i + "").start();

        }

这个问题是add方法引起的问题。

看下add方法的源码:

    public boolean add(E e) {
        //扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //赋值
        elementData[size++] = e;
        return true;
    }

在网上搜索了一下相关问题,有的说是应为扩容所导致的,有的说是赋值使用size++导致的,经过分析个人任务是使用size++导致的。因为size++是非原子性的,多线程情况下会出现问题。

elementData[size++] = e;可为两步

1.给索引位置赋值

2.size加1

如果现在有两个线程a,b,size为5,a线程读到索引位值时,将值赋值到这个位置,这时cpu时间片让出,b线程读到的size也是5(因为a线程没有执行加1操作就将时间片让出来了),b线程将值赋值到size=5这个位置,然后size加1。这个时候a线程恢复cpu时间片,size再加1。这样,a线程和b线程都赋值到了size=5这个位置,索引位置值变成了a线程赋值的值,b线程的值被覆盖了,但是size却加了2次,最后size经过两次加1变成了7,size=6这个这个下标的值就会为null.

ArrayList底层的数据结构是数组,数组里面对应下标没有值就是null.

举例:

        Integer[] elementData = new Integer[22];
        int size = 0;
        for (int i = 0; i< 10; i++) {
            elementData[size] = i;
            size = size + 2;
        }
        System.out.println(Arrays.toString(elementData));


 

3.数组下标越界问题

数组越界异常 ArrayIndexOutOfBoundsException

由于ArrayList添加元素是如上面分两步进行,可以看出第一个不安全的隐患,在多个线程进行add操作时可能会导致elementData数组越界。具体逻辑如下:

  1. 列表大小为9,即size=9
  2. 线程A开始进入add方法,这时它获取到size的值为9,调用ensureCapacityInternal方法进行容量判断。
  3. 线程B此时也进入add方法,它获取到size的值也为9,也开始调用ensureCapacityInternal方法。
  4. 线程A发现需求大小为10,而elementData的大小就为10,可以容纳。于是它不再扩容,返回。
  5. 线程B也发现需求大小为10,也可以容纳,返回。
  6. 线程A开始进行设置值操作, elementData[size++] = e 操作。此时size变为10。
  7. 线程B也开始进行设置值操作,它尝试设置elementData[10] = e,而elementData没有进行过扩容,它的下标最大为9。于是此时会报出一个数组越界的异常ArrayIndexOutOfBoundsException.

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

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

相关文章

【从入门到起飞】JavaSE—方法引用

&#x1f38a;专栏【JavaSE】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【The truth that you leave】 &#x1f970;欢迎并且感谢大家指出我的问题 文章目录 &#x1f354;概述&#x1f354;注意&#x1f388;如何确定是否是…

电脑msvcr100.dll丢失的解决方法,找不到msvcr100.dll的修复方法分享

msvcr100.dll 丢失是一种常见的软件运行错误&#xff0c;通常会在运行某些程序时出现。这个问题可能是由于多种原因导致的&#xff0c;例如病毒感染、软件损坏、卸载应用程序时误删除文件等。为了解决这个问题&#xff0c;我们需要采取一些措施来恢复 msvcr100.dll 文件。 一、…

heic图片如何转为jpg格式

heic图片如何转为jpg格式&#xff1f;现阶段&#xff0c;在技术水平不断完善的基础上&#xff0c;图片质量越来越好了&#xff0c;且图片数量也越来越多。图片内容不断丰富&#xff0c;导致图片格式愈发多样化。为了能够保证图片的有效应用&#xff0c;我们有的时候需要将图片格…

一台PoE交换机可以为多少个设备提供供电?

如今在安防监控领域&#xff0c;许多网络设备都支持PoE供电。在网络监控工程中&#xff0c;为了节省布线成本并提高便捷性&#xff0c;大多数工程商选择使用PoE供电方案&#xff0c;也就是使用PoE交换机为监控摄像头提供电力。那么&#xff0c;一台功率输出以太网&#xff08;P…

可以创业,也可以副业的网上长期挣钱的项目

在这个飞速发展的互联网时代&#xff0c;越来越多的人开始尝试在网上创业或者寻找一份可持续的副业来增加收入。不过在网上赚钱的难度是比较大的&#xff0c;不是轻易就能做到的&#xff0c;所以不付出一番努力&#xff0c;没有悟性和执行力&#xff0c;那么是很难做好的&#…

MongoDB【部署 04】Windows系统实现MongoDB多磁盘存储

Windows系统实现多磁盘存储 1.为什么2.多磁盘存储2.1 数据库配置2.2 文件夹磁盘映射2.3 创建新的数据集 3.总结 1.为什么 这里仅针对只有一台Windows系统服务器的情景&#xff1a; 当服务器存储不足时&#xff0c;或者要接入更多的数据&#xff0c;就会挂载新磁盘&#xff0c…

Vim编辑器使用入门

目录 一、Vim 编辑器基础操作 二、Vim 编辑器进阶操作 三、Vim 编辑器高级操作 四、Vim 编辑器文件操作 五、Vim 编辑器文件管理 六、Vim 编辑器进阶技巧 七、Vim 编辑器增强功能 Vim的三种工作模式 一、Vim 编辑器基础操作 1.移动光标 - 光标的移动控制 移动光标有两…

JS手动实现发布者-订阅者模式

发布-订阅模式是一种对象间一对多的依赖关系&#xff0c;当一个对象的状态发送改变时&#xff0c;所有依赖于它的对象都将得到状态改变的通知。具体过程是&#xff1a;订阅者把自己想订阅的事件注册到调度中心&#xff0c;当发布者更新该事件时通知调度中心&#xff0c;由调度中…

python每日一题(模拟用户登录验证)

1、题目 预先设定正确用户名与密码&#xff0c;用来验证用户是否登录成功。 第一次&#xff1a; ① 输入用户名与密码&#xff0c;如果用户名与密码正确&#xff0c;则提示登录成功&#xff1b; ② 如果用户名错误&#xff08;不管密码是否正确&#xff09;&#xff0c;则需要重…

【NetEQ】读 《白话解读 WebRTC 音频 NetEQ 及优化实践》学习笔记

白话解读 WebRTC 音频 NetEQ 及优化实践webrtc 的重要模块 官方文档 :转载请标明出处:大神翻译 大神地址 : https://blog.csdn.net/lhl_blog/article/details/10993605GIPS NetEQ概述 GIPS NetEQ是一项专为IP电信系统开发的高级语音质量处理技术,其能够在大幅提高语音质量的…

ros 接收相机数据数据并发布

完整这个任务不需要用到python3 效果如下所示 环境 ROS1 python2.7 原始环境 无conda 或者conda deactivate 无conda 状态 pip install rospkg pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python4.2.0.3 代码 放在工程目录中 #!/usr/bin/env …

stm32学习笔记:OLED显示屏

一、OLED简介 OLED:有机发光二极管&#xff0c;供电∶3~5.5V&#xff0c;通信协议︰I2C/SPI&#xff0c;分辨率∶12864 二、常用的调试方式 串口调试∶通过串口通信&#xff0c;将调试信息发送到电脑端&#xff0c;电脑使用串口助手显示调试信息 显示屏调试∶直接将显示屏连接…

龙讯旷腾机器学习力场PWMLFF V0.1.0——优化件lammps接口,提供主动学习方案

PWMLFF&#xff08;机器学习力场&#xff09;手册 http://doc.lonxun.com/PWMLFF/ 我们都知道从第一性原理出发的分子动力学&#xff08;Ab Initio Molecular Dynamics, AIMD&#xff09;计算非常精确&#xff0c;但需要消耗大量时间和计算资源&#xff0c;能模拟的空间尺度和…

代码随想录算法训练营第59天 | ● 503.下一个更大元素II ● 42. 接雨水

文章目录 前言一、503.下一个更大元素II二、42. 接雨水总结 前言 单调栈&#xff1b; 一、503.下一个更大元素II 循环的问题&#xff1a;1.多建立一个数组 2.采用取模的方法&#xff1b; 问题&#xff1a;采用取模&#xff0c;后面的值会被前面的覆盖掉吗&#xff1f; 答&am…

宁波融资融券开户利息率最低是多少?两融利率5%或以下!

宁波融资融券开户利息率最低是多少?两融利率5%或以下&#xff01; 融资融券是指投资者通过借入资金融资&#xff0c;或者借入证券卖出并借入资金购买证券&#xff0c;以达到增加投资收益的一种交易方式。融资融券交易需要满足一定的条件&#xff0c;如投资者必须拥有一定的股…

Go 围炉札记

文章目录 一、Go 安装 一、Go 安装 VScode下配置Go语言开发环境【2023最新】 基础篇&#xff1a;新手使用vs code新建go项目 vscode里安装Go插件和配置Go环境 Documentation Golang 配置代理 Go命令详解 一文详解Go语言常用命令 Go 语言教程 熬夜整理&#xff0c;最全的Go语…

阿里云效自动构建python自动测试脚本

之前一直用的是jenkins自动构建自动化脚本&#xff0c;因为现在的公司统一在阿里云效的流水线上做代码的管理&#xff0c;构建&#xff0c;要求自动化测试也在上面自动构建&#xff0c;故而学习了一下。为自己做一个记录&#xff0c;也给有需要的朋友做一个参考。 1. 新建流水…

大厂面试-16道面试题

1 java集合类有哪些&#xff1f; List是有序的Collection&#xff0c;使用此接口能够精确的控制每个元素的插入位置&#xff0c;用户能根据索引访问List中元素。常用的实现List的类有LinkedList&#xff0c;ArrayList&#xff0c;Vector&#xff0c;Stack。 ArrayList是容量…

python 为 网易云下载的 本地音乐文件增加 序号

前言 网易云下载的音乐文件&#xff0c;信息挺全的&#xff0c;但是缺少序号&#xff0c;用本地播放器听是乱序的&#xff0c;就很头疼。 遂写一个python脚本解决问题 本python会把基于音乐文件的元信息&#xff0c;重命名文件 到 以下格式 序号 标题.后缀 额外依赖库 muta…

工时表软件如何彻底改变时间跟踪工作?

在工作场所&#xff0c;生产率的下降一直在消耗我们的精力和钱包。你知道吗&#xff0c;每年仅生产力倦怠一项&#xff0c;每位员工就会给企业造成 1,967 美元的惊人损失&#xff01; 好消息是&#xff0c;有一种创新的解决方案可以解决这种生产力下降的问题&#xff0c;它就是…