Java中LinkedList遍历删除触发ConcurrentModificationException问题求助
我是编程新手,在Java的Produktions_Manager线程的run方法中,使用增强for循环遍历LinkedList<Bestellung> bestellungenInProduktion时遇到问题:同时提交3个及以上订单时,首个订单生产完成后会抛出java.util.ConcurrentModificationException;仅提交1-2个订单时运行正常。尝试过使用Iterator、添加sleep等方法均未解决,希望在不更换LinkedList的前提下找到解决方案。
报错信息
Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.base/java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:970)
at java.base/java.util.LinkedList$ListItr.next(LinkedList.java:892)
at Produktions_Manager.run(Produktions_Manager.java:88)
相关代码
public class Produktions_Manager extends Thread { // 初始化所有实例变量 private Holzbearbeitungs_Roboter holzroboter; // 机器人 private Montage_Roboter montageroboter; private Lackier_Roboter lackierroboter; private Verpackungs_Roboter verpackungsroboter; private Fabrik meineFabrik; // 我的工厂 private Lager meinLager; // 我的仓库 private LinkedList<Bestellung> zuVerarbeitendeBestellungen; // 待处理订单 private LinkedList<Bestellung> bestellungenInProduktion; // 生产中订单 /** * Produktions_Manager类的构造函数初始化并启动所有机器人,同时初始化待处理订单和生产中订单的LinkedList。 * * @param meineFabrik 要启动的工厂 * @param meinLager 要启动的仓库 */ public Produktions_Manager(Fabrik meineFabrik, Lager meinLager) { holzroboter = new Holzbearbeitungs_Roboter("Holzroboter"); montageroboter = new Montage_Roboter("Montageroboter"); lackierroboter = new Lackier_Roboter("Lackierroboter"); verpackungsroboter = new Verpackungs_Roboter("Verpackungsroboter"); holzroboter.start(); montageroboter.start(); lackierroboter.start(); verpackungsroboter.start(); this.meineFabrik = meineFabrik; this.meinLager = meinLager; zuVerarbeitendeBestellungen = new LinkedList<Bestellung>(); bestellungenInProduktion = new LinkedList<Bestellung>(); } /** * 该方法在无限循环中检查是否有新订单到达。 * 如果收到订单,将其从待处理订单列表中移除并添加到生产中订单列表,随后启动生产。 */ @Override public void run() { ThreadUtil.syncedPrintln("生产管理器已启动"); while (true){ // 有新订单到达时,获取下一个订单并启动生产 Bestellung naechsteBestellung = zuVerarbeitendeBestellungen.peek(); if(naechsteBestellung == null){ ThreadUtil.syncedPrintln("[生产管理器] 无待处理订单"); } else { ThreadUtil.syncedPrintln("[生产管理器] 有新的待处理订单"); } if(naechsteBestellung != null && meinLager.lagerbestandPruefenUndNachbestellen(naechsteBestellung)){ naechsteBestellung = zuVerarbeitendeBestellungen.poll(); bestellungenInProduktion.add(naechsteBestellung); naechsteBestellung.setzeBestellstatus(2); ThreadUtil.syncedPrintln("[生产管理器] 开始生产订单 " + naechsteBestellung.gibBestellungsNr()); for(Produkt produkt : naechsteBestellung.liefereBestellteProdukte()){ roboterzuweisung(produkt); produkt.naechsteProduktionsstation(); } } // 异常抛出位置 for (Bestellung bestellung : bestellungenInProduktion){ // 遍历生产中订单 boolean alleProdukteProduziert = true; // 所有产品已生产完成 for(Produkt produkt : bestellung.liefereBestellteProdukte()){ // 获取订单中的产品 if(produkt.gibAktuellenZustand()!=3){ // 检查产品当前状态是否为已完成 alleProdukteProduziert = false; break; } } if(alleProdukteProduziert == true){ bestellungenInProduktion.remove(bestellung); bestellung.setzeAlleProdukteProduziert(); } } // 生产管道中无订单时的提示信息 if(bestellungenInProduktion.size() == 0){ ThreadUtil.syncedPrintln("[生产管理器] 生产管道中无订单 - 机器人无生产任务。"); } else { ThreadUtil.syncedPrintln("[生产管理器] 仍有订单在生产中。"); } ThreadUtil.sleep(5000); } } }
问题根源:你遇到的ConcurrentModificationException是因为在增强for循环遍历集合时直接修改了集合(调用bestellungenInProduktion.remove(bestellung))。增强for循环底层依赖Iterator实现,Iterator的fail-fast机制会检测到集合结构被修改(modCount和expectedModCount不一致),从而抛出异常。1-2个订单时偶然正常是因为遍历到最后一个元素时删除,不会触发后续的next()检查,属于巧合。
以下是两种不更换LinkedList的有效解决办法:
方法1:使用Iterator的remove方法(推荐)
Iterator本身提供了安全的remove方法,它会同步更新modCount和expectedModCount,避免异常。把原来的增强for循环改成Iterator遍历:
Iterator<Bestellung> iterator = bestellungenInProduktion.iterator(); while (iterator.hasNext()) { Bestellung bestellung = iterator.next(); boolean alleProdukteProduziert = true; for(Produkt produkt : bestellung.liefereBestellteProdukte()){ if(produkt.gibAktuellenZustand()!=3){ alleProdukteProduziert = false; break; } } if(alleProdukteProduziert){ iterator.remove(); // 使用Iterator的remove方法,而非集合的remove bestellung.setzeAlleProdukteProduziert(); } }
你之前尝试Iterator没解决,大概率是误用了集合的remove方法,而不是Iterator自身的remove。
方法2:先收集待删除元素,再批量删除
先遍历集合找出所有完成的订单,存入临时列表,之后一次性从原集合中删除这些元素,避免遍历过程中修改集合:
List<Bestellung> abgeschlosseneBestellungen = new ArrayList<>(); // 第一步:收集所有已完成的订单 for (Bestellung bestellung : bestellungenInProduktion) { boolean alleProdukteProduziert = true; for(Produkt produkt : bestellung.liefereBestellteProdukte()){ if(produkt.gibAktuellenZustand()!=3){ alleProdukteProduziert = false; break; } } if(alleProdukteProduziert){ abgeschlosseneBestellungen.add(bestellung); bestellung.setzeAlleProdukteProduziert(); } } // 第二步:批量删除已完成的订单 bestellungenInProduktion.removeAll(abgeschlosseneBestellungen);
额外注意点
如果有其他线程也在修改bestellungenInProduktion集合(比如机器人线程更新订单状态时修改集合),还需要给集合加同步锁,或者用Collections.synchronizedList(new LinkedList<>())包装集合,同时遍历的时候手动加锁:
// 初始化时包装集合 bestellungenInProduktion = Collections.synchronizedList(new LinkedList<Bestellung>()); // 遍历前加锁 synchronized (bestellungenInProduktion) { // 这里放遍历删除的代码(方法1或方法2) }
不过从当前代码看,修改集合的操作都在Produktions_Manager的run方法里,大概率是单线程内的问题,前两种方法就能解决。
内容的提问来源于stack exchange,提问作者patville

