You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 19:20:12