ArrayList在添加元素时报错java.lang.ArrayIndexOutOfBoundException

一、添加单个元素数组越界分析

add源码如下

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

size字段的定义

The size of the ArrayList (the number of elements it contains).

ArrayList的大小(包含元素的个数)
elementData[size++]=e
此代码分2个步骤,先执行赋值,既elementData[size]=e,然后在执行size++

模拟越界场景
定义一个数组长度为10
ArrayList list = new ArrayList(10);
假设已经添加九个元素,所以size = 9
thread 1执行add,会判断ensureCapacityInternal(size + 1),size + 1<10,不进行扩容
thread 2执行add,会判断ensureCapacityInternal(size + 1),size + 1<10,不进行扩容
以上thread 1和thread 2同时运行
thread 1执行elementData[size++] = e;此时size++后等于10
thread 2执行elementData[size++] = e;此时size==10, elementData[10]抛出out of index错误

  
因此验证在并行情况下,扩容临界值执行add会数组越界

二、添加集合越界分析

addList源码

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

数组越界原理同上,两个线程都刚好执行ensureCapacityInternal(size + numNew);且都不需要进行扩容,
在执行System.arraycopy(a, 0, elementData, size, numNew)发生越界

三、解决方案并分析

使用Collections.synchronizedList(new ArrayList<>())替代ArrayList
如果是读多写少的场景,使用CopyOnWriteArrayList替代ArrayList

collections源码分析

public static <T> List<T> synchronizedList(List<T> list) {
	return (list instanceof RandomAccess ?
			new SynchronizedRandomAccessList<>(list) :
			new SynchronizedList<>(list));
}

最终new 出SynchronizedRandomAccessList类

static class SynchronizedRandomAccessList<E>
	extends SynchronizedList<E>
	implements RandomAccess

SynchronizedRandomAccessList继承SynchronizedList

static class SynchronizedList<E>
	extends SynchronizedCollection<E>
	implements List<E> {

接着又继承SynchronizedCollection

static class SynchronizedCollection<E> implements Collection<E>, Serializable {
        private static final long serialVersionUID = 3053995032091335093L;

        final Collection<E> c;  // Backing Collection
        final Object mutex;     // Object on which to synchronize

        SynchronizedCollection(Collection<E> c) {
            this.c = Objects.requireNonNull(c);
            mutex = this;
        }

        SynchronizedCollection(Collection<E> c, Object mutex) {
            this.c = Objects.requireNonNull(c);
            this.mutex = Objects.requireNonNull(mutex);
        }

        public int size() {
            synchronized (mutex) {return c.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return c.isEmpty();}
        }
        public boolean contains(Object o) {
            synchronized (mutex) {return c.contains(o);}
        }
        public Object[] toArray() {
            synchronized (mutex) {return c.toArray();}
        }
        public <T> T[] toArray(T[] a) {
            synchronized (mutex) {return c.toArray(a);}
        }

        public Iterator<E> iterator() {
            return c.iterator(); // Must be manually synched by user!
        }

        public boolean add(E e) {
            synchronized (mutex) {return c.add(e);}
        }
        public boolean remove(Object o) {
            synchronized (mutex) {return c.remove(o);}
        }

        public boolean containsAll(Collection<?> coll) {
            synchronized (mutex) {return c.containsAll(coll);}
        }
        public boolean addAll(Collection<? extends E> coll) {
            synchronized (mutex) {return c.addAll(coll);}
        }
        public boolean removeAll(Collection<?> coll) {
            synchronized (mutex) {return c.removeAll(coll);}
        }
        public boolean retainAll(Collection<?> coll) {
            synchronized (mutex) {return c.retainAll(coll);}
        }
        public void clear() {
            synchronized (mutex) {c.clear();}
        }
        public String toString() {
            synchronized (mutex) {return c.toString();}
        }
        // Override default methods in Collection
        @Override
        public void forEach(Consumer<? super E> consumer) {
            synchronized (mutex) {c.forEach(consumer);}
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            synchronized (mutex) {return c.removeIf(filter);}
        }
        @Override
        public Spliterator<E> spliterator() {
            return c.spliterator(); // Must be manually synched by user!
        }
        @Override
        public Stream<E> stream() {
            return c.stream(); // Must be manually synched by user!
        }
        @Override
        public Stream<E> parallelStream() {
            return c.parallelStream(); // Must be manually synched by user!
        }
        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

看得出,使用了final Collection<E> c存放具体集合类,
每个方法使用synchronized进行同步限制,锁对象为mutex=this,

四、总结

1.ArrayList不适合多线程场景使用
2.线程安全List有Collections.synchronizedList和CopyOnWriteArrayList
3.Collections集合类很多好用的方法,注意Collection是接口,写法上区分有没有s
4.静态内部类synchronizedList 继承-> SynchronizedRandomAccessList 继承-> SynchronizedCollection
5.除了静态内部类synchronizedList,同理有静态内部类synchronizedSet和静态内部类synchronizedMap

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【面试官问】Redis 持久化

目录 【面试官问】Redis 持久化 Redis 持久化的方式RDB(Redis DataBase)AOF(Append Only File)混合持久化:RDB + AOF 混合方式的持久化持久化最佳方式控制持久化开关主从部署使用混合持久化使用配置更高的机器参考文章所属专区

【Django】Cookie和Session的使用

Cookies和Session 1. 会话 从打开浏览器访问一个网站&#xff0c;到关闭浏览器结束此次访问&#xff0c;称之为一次会话。 HTTP协议是无状态的&#xff0c;导致会话状态难以保持。 Cookies和Session就是为了保持会话状态而诞生的两个存储技术。 2. Cookies 2.1 Cookies定…

机器学习系列——(六)数据降维

引言 在机器学习领域&#xff0c;数据降维是一种常用的技术&#xff0c;旨在减少数据集的维度&#xff0c;同时保留尽可能多的有用信息。数据降维可以帮助我们解决高维数据带来的问题&#xff0c;提高模型的效率和准确性。本文将详细介绍机器学习中的数据降维方法和技术&#…

【Linux取经路】进程控制——程序替换

文章目录 一、单进程版程序替换看现象二、程序替换的基本原理三、程序替换接口学习3.1 替换自己写的可执行程序3.2 第三个参数 envp 验证四、结语一、单进程版程序替换看现象 #include <stdio.h> #

Vue学习笔记之组件基础

1、组件的定义 一般将 Vue 组件定义在一个单独的 .vue 文件中&#xff0c;称做单文件组件&#xff1b;当然也可以将组件直接定义在js文件中&#xff0c;如下js代码&#xff0c;定义一个组件BlogPost&#xff0c;通过props定义对外暴露属性title&#xff0c;父组件传递title&am…

List的模拟实现 迭代器

———————————————————— list与vector相比&#xff0c;插入、删除等操作实现的成本非常低&#xff0c;如果在C语言阶段熟悉理解过链表&#xff0c;那么现在实现起来list就显得比较简单&#xff0c;可以说操作层面上比vector更简洁&#xff0c;因为list没有扩…

C++ 动态规划 线性DP 最长上升子序列

给定一个长度为 N 的数列&#xff0c;求数值严格单调递增的子序列的长度最长是多少。 输入格式 第一行包含整数 N 。 第二行包含 N 个整数&#xff0c;表示完整序列。 输出格式 输出一个整数&#xff0c;表示最大长度。 数据范围 1≤N≤1000 &#xff0c; −109≤数列中的数…

istio 限流

#详细参数看官网&#xff0c;我参数就不解释https://istio.io/latest/docs/reference/config/networking/destination-rule/cat << EOF > dr.yaml apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata:name: my-testnamespace: demon spec:hos…

瑞_23种设计模式_抽象工厂模式

文章目录 1 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;1.1 概念1.2 介绍1.3 小结1.4 结构 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 总结4.1 抽象工厂模式优缺点4.2 抽象工厂模式使用场景4.3 抽象工厂模式 VS 工厂方法模式4.4 抽象工…

记一次生产系统每隔10小时(36000000毫秒)固定进行一次Full GC排查思路

一、 背景描述 某个应用在生产环境通过系统监控发现&#xff0c;应用每隔10小时就会触发一次Full GC&#xff0c;该系统当时承接的业务量并不大&#xff0c;而且固定10小时就会进行Full GC&#xff0c;通过监控时间轴发现Full GC频率很规律&#xff0c;直觉告诉我这不是JVM自身…

回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测(SE注意力机制)

回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&#xff09; 目录 回归预测 | Matlab实现RIME-CNN-LSTM-Attention霜冰优化卷积长短期记忆网络注意力多变量回归预测&#xff08;SE注意力机制&#xff0…

计算机网络-差错控制(奇偶校验码 CRC循环冗余码)

文章目录 差错从何而来从传感器层面提高信道比来减少线路本身的随机噪声的一个例子热噪声和冲击噪声 数据链路层的差错控制检错编码-奇偶校验码检错编码-CRC循环冗余码例子注意 差错从何而来 噪声通常指的是任何未预期的、随机的信号干扰&#xff0c;这些干扰可能源自多种物理…

Python脚本自动去除文档中无用的信息

1.在进行嵌入式开发过程中会遇到此类情况&#xff1a; 想去掉文档中的“//0x20”的信息&#xff0c;手动消除的话会很麻烦&#xff0c;这时用python脚本就很方便。 2.源码&#xff1a; #!/usr/bin/python3# 打开一个文件 f open("test.txt", "r")text …

LabVIEW智能温度直流模件自动测试系统

LabVIEW智能温度直流模件自动测试系统 自动化测试系统在提高测试效率和准确性方面发挥着越来越重要的作用。介绍了一种基于LabVIEW的智能温度直流模件&#xff08;TDCA&#xff09;自动测试系统的设计与实施&#xff0c;旨在提高测控装置的产品质量。 系统的硬件平台主要由PS…

【Boost】:searcher的建立(四)

searcher的建立 一.初始化二.搜索功能三.完整源代码 sercher主要分为两部分&#xff1a;初始化和查找。 一.初始化 初始化分为两步&#xff1a;1.创建Index对象&#xff1b;2.建立索引 二.搜索功能 搜索分为四个步骤 分词&#xff1b;触发&#xff1a;根据分词找到对应的文档…

P4071 [SDOI2016] 排列计数 错排,递归公式

错排公式理解&#xff1a; //f(x)表示1~x的错排数目 // //1选择(x-1种&#xff09; //乘以剩下的总数目就是答案。//(1选了2就接着排2了&#xff0c;这样所有的都可以算到&#xff0c;是递归所以难想)// 选2时 // 2可选 1 和 3~x//2选1&#xff0c;对2开始来说此次总数就是1*f(…

Linux权限【超详细】

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 扩展知识&#xff1a…

C++项目 -- 高并发内存池(二)Thread Cache

C项目 – 高并发内存池&#xff08;二&#xff09;Thread Cache 文章目录 C项目 -- 高并发内存池&#xff08;二&#xff09;Thread Cache一、高并发内存池整体框架设计二、thread cache设计1.整体设计2.thread cache哈希桶映射规则3.TLS无锁访问4.thread cache代码 一、高并发…

【数据分享】1米分辨率土地覆盖数据集SinoLC-1

数据链接 SinoLC-1: the first 1-meter resolution national-scale land-cover map of China created with the deep learning framework and open-access data (Update data: August, 2023) (zenodo.org)https://zenodo.org/records/8214467 数据分享 数据分享到了公众号&…

2024/2/4

一&#xff0e;选择题 1、下列不能作为类的成员的是&#xff08;B&#xff09; A. 自身类对象的指针 B. 自身类对象 C. 自身类对象的引用 D. 另一个类的对象 2、假定AA为一个类&#xff0c;a()为该类公有的函数成员&#xff0c;x为该类的一个对象&#xff0c;则访问x对象中…