使用ArrayList.add()随机抛出ArrayIndexOutOfBoundsException问题求助
ArrayList无参add()抛出ArrayIndexOutOfBoundsException(索引-1)排查方案
核心原因
从异常堆栈和随机出现的现象来看,根本问题是线程不安全的ArrayList在多线程并发环境下被修改,导致内部状态损坏。
ArrayList本身不支持并发操作,当多个线程同时执行add、扩容等操作时,会破坏其内部的size、elementData数组等状态的一致性。比如:
- 线程A正在执行扩容逻辑,修改了elementData数组的长度;
- 线程B同时修改size变量,可能导致size被错误地更新为-1;
- 后续执行add()时,基于损坏的size计算索引,就会抛出
ArrayIndexOutOfBoundsException: Index -1 out of bounds异常。
代码疑点说明
你提供的代码片段中,_launchedRequestsMap是局部变量,不存在多线程共享问题,这段代码如果触发异常应该是NullPointerException(当requestLaunchType不存在时),和当前异常无关。实际问题出在TestRequestPoolSingleton.addToLaunched方法中维护的共享ArrayList实例。
解决方案
针对多线程环境下的集合操作,推荐以下几种修复方式:
- 替换为线程安全集合:将共享的ArrayList替换为
Collections.synchronizedList(new ArrayList<>()),或者CopyOnWriteArrayList(适合读多写少的场景,写操作会复制整个数组,性能开销较大)。 - 手动加锁保护:在所有操作该共享ArrayList的代码块上添加
synchronized锁,或者使用ReentrantLock保证同一时间只有一个线程修改集合状态。示例:
// 在TestRequestPoolSingleton中加锁 private final List<String> launchedRequests = new ArrayList<>(); private final Object lock = new Object(); public void addToLaunched(String requestId) { synchronized(lock) { launchedRequests.add(requestId); } }
- 检查单例类的线程安全:确认
TestRequestPoolSingleton的实现是否存在线程不安全的初始化或访问逻辑,确保共享集合的所有操作都经过线程安全处理。
验证点
- 确认
TestRequestPoolSingleton中的ArrayList是否为多线程共享的单例实例; - 查看
addToLaunched方法的实现,是否存在未加锁的并发修改操作。
内容的提问来源于stack exchange,提问作者Madhusudan
相关产品推荐
相关产品推荐

