Java多线程生成ConcurrentModificationException场景的问题咨询
问题分析与解决方案
原代码抛出IllegalThreadStateException的原因
你原代码的问题出在重复启动同一个线程:
- Thread类的
start()方法只能调用一次,调用后线程会从NEW状态进入RUNNABLE状态,后续再次调用start()就会抛出IllegalThreadStateException。 - 你用
l.forEach()遍历列表(初始有4个元素),每次遍历都会执行t1.start()和t2.start(),相当于每个线程被启动了4次,第一次启动后线程状态不再是NEW,后续启动操作直接触发异常。
正确触发ConcurrentModificationException的多线程示例
首先要明确:CopyOnWriteArrayList是线程安全的集合,它采用写时复制机制,遍历操作会基于列表的快照进行,所以不会抛出ConcurrentModificationException。要触发这个异常,得用非线程安全的集合(比如ArrayList),结合多线程下的遍历+修改操作。
以下是符合需求的示例代码:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ConcurrentModificationDemo { public static void main(String[] args) { // 使用非线程安全的ArrayList,这是触发异常的前提 List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4)); // 线程1:遍历列表(依赖ArrayList的fail-fast迭代器) Thread thread1 = new Thread(() -> { try { // 延迟100ms,让线程2先开始修改列表 Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } // for-each循环本质是用迭代器遍历,会触发fail-fast检查 for (Integer num : list) { System.out.println("线程1遍历元素:" + num); try { // 每次遍历后延迟,放大并发冲突的概率 Thread.sleep(50); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); // 线程2:修改列表结构(添加元素) Thread thread2 = new Thread(() -> { try { // 延迟50ms,确保线程1已经准备好遍历 Thread.sleep(50); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } for (int i = 5; i < 8; i++) { System.out.println("线程2添加元素:" + i); list.add(i); try { Thread.sleep(50); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); thread1.start(); thread2.start(); } }
异常触发原理
ArrayList的迭代器实现了fail-fast机制:迭代器初始化时会记录当前列表的修改次数modCount,遍历过程中每次都会检查这个值是否和预期一致。如果另一个线程修改了列表的结构(比如add/remove操作),modCount会递增,此时迭代器发现值不一致,就会抛出ConcurrentModificationException。
内容的提问来源于stack exchange,提问作者D_B
相关产品推荐
相关产品推荐

