在Java的run方法中实现一个针对LinkedList的for循环:并发修改异常

ttp71kqs  于 2023-01-01  发布在  Java
关注(0)|答案(1)|浏览(126)

我正在寻找一个解决问题的方法,我想象是相当简单,但不能弄清楚一些原因。因为我刚刚开始编程几个星期前,我敢肯定,这段代码可能有点不完美的书面,所以请容忍我。
我的问题与代码,是它抛出一个异常在for循环“for(Bestellung bestellung:bestellungenInProduktion){”(代码的下三分之一;标记注解)只要我同时“提交”3个或更多的“订单”,而当同时只提交1或2个订单时,它运行得非常好。
在提交3个或更多订单时,第一个订单会正常处理,但在完成第一个订单的生产后,它会立即抛出异常。错误消息为:

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)

这就是所讨论的代码(抛出异常的行比最后一行大约高出25行):

public class Produktions_Manager extends Thread
{
    // Initiates all instant variables. 
    private Holzbearbeitungs_Roboter holzroboter; // robots
    private Montage_Roboter montageroboter;
    private Lackier_Roboter lackierroboter;
    private Verpackungs_Roboter verpackungsroboter;

    private Fabrik meineFabrik; //myFactory
    private Lager meinLager; //myStorage
    
    private LinkedList<Bestellung> zuVerarbeitendeBestellungen; //ordersToBeCompleted
    private LinkedList<Bestellung> bestellungenInProduktion; //ordersInProduction

    /**
     * The constructor of the Produktions_Manager class instantiates and starts
     * all robots. In also opens the LinkedLists for the orders to be processed
     * and for the orders in production.
     * 
     * @param   meineFabrik   die Fabrik, die eröffnet wird
     * @param   meinLager     das Lager, das eröffnet wird
     */
    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>();
    }
    
    /**
     * This method checks in an infinite loop if a new order has arrived.
     * If an order has been received, it is removed from the list of orders to be processed
     * and added to the list of products to be produced. Subsequently, the production is started.
     */

    @Override public void run()
    {
        ThreadUtil.syncedPrintln("Produktionsmanager wurde gestartet");
        
        while (true){    //When a new order has arrived, then get the next order and start production.

            Bestellung naechsteBestellung = zuVerarbeitendeBestellungen.peek();
            
            if(naechsteBestellung == null){
                ThreadUtil.syncedPrintln("[Produktions_Manager] keine Bestellung zu verarbeiten");
            } else {
                ThreadUtil.syncedPrintln("[Produktions_Manager] neue Bestellung zu verarbeiten");
            }
                        
            if(naechsteBestellung != null && meinLager.lagerbestandPruefenUndNachbestellen(naechsteBestellung)){
                naechsteBestellung = zuVerarbeitendeBestellungen.poll();          
                bestellungenInProduktion.add(naechsteBestellung); 
                naechsteBestellung.setzeBestellstatus(2);
                
                ThreadUtil.syncedPrintln("[Produktions_Manager] startet die Produktion von " + naechsteBestellung.gibBestellungsNr());
                
                for(Produkt produkt : naechsteBestellung.liefereBestellteProdukte()){
                    roboterzuweisung(produkt);
                    produkt.naechsteProduktionsstation();
                }
            }
            
            //The next line is where the exception is thrown.

            for (Bestellung bestellung : bestellungenInProduktion){ //Order order : ordersInProduction
                boolean alleProdukteProduziert = true; //allItemsProduced
                for(Produkt produkt : bestellung.liefereBestellteProdukte()){ //order.deliverOrdererItems
                    if(produkt.gibAktuellenZustand()!=3){ //product.giveCurrentState
                        alleProdukteProduziert = false; //allItemsProduced
                        break;
                    }
                }
                
                if(alleProdukteProduziert == true){
                 bestellungenInProduktion.remove(bestellung);
                 bestellung.setzeAlleProdukteProduziert();
                 
                }
            }

            //Zusätzliche Meldung, falls keine Bestellungen in der Produktions-Pipeline stehen
            if(bestellungenInProduktion.size() == 0){
                ThreadUtil.syncedPrintln("[Produktions_Manager] keine neuen Bestellungen für Produktion - Roboter können nichts produzieren.");
            } else {
                ThreadUtil.syncedPrintln("[Produktions_Manager] es sind noch Bestellungen in Produktion.");
            }
            
            ThreadUtil.sleep(5000);
            
        }
    }
}

因为它可以处理同时提交的1个和2个订单,所以我希望它也可以处理更多订单,但似乎有一个同步问题,我找不到解决方案。
我尝试使用迭代器(我用不同的方法尝试了很多个小时),以及添加睡眠(在单独的类中;在其他地方都有效)在不同的地方持续不同的时间(因为那之前已经为我解决了一些问题),所有这些都没有起作用。
不幸的是,如果不使用LinkedList,就意味着我的代码几乎要从头开始,因此,如果可能的话,我希望用另一种解决方法来解决这个问题。
如果有人能帮助我或给我指出正确的方向,我将不胜感激。如果需要任何进一步的信息,我一定会尽快添加到这个帖子。

7hiiyaii

7hiiyaii1#

如果我理解正确的话,你有一个for循环遍历一个列表(bestellungInProduktion),在这个循环中,你调用列表上的List::remove,这将导致ConcurrentModificationException,正如预期的那样。
在内部,增强的for循环在该列表上创建了一个迭代器,并且通过从列表中删除(或添加)一个元素,该迭代器将失去同步。
如果你想从列表中删除一个你正在迭代的条目,你必须调用Iterator::remove

for( final var i = bestellungenInProduktion.listIterator(); i.hasNext(); )
{ 
  var alleProdukteProduziert = true;
  final var bestellung = i.next;
  for( final var produkt : bestellung.liefereBestellteProdukte() )
  { 
    if( produkt.gibAktuellenZustand() != 3 )
    {
      alleProdukteProduziert = false;
      break;
    }
  }
                
  if( alleProdukteProduziert )
  {
    i.remove();
    bestellung.setzeAlleProdukteProduziert();
  }
}

相关问题