ArrayList抛出错误:来自不同类中的代码的“并发修改异常”

时间:2016-08-01 16:47:23

标签: java arraylist

我知道这是一个经常被问到的问题,但我仍然坚持如何用我的代码解决它。

我的GUI上有一个按钮,允许我在图形窗口中添加额外的“海龟”,这会在游戏循环结构中向一个显示植绒行为的arraylist添加一只乌龟。我怎么能这样做,所以我可以添加尽可能多的海龟,而不显示这个错误?

游戏循环如下:

private void gameLoop() 
    {       
        while(true) //The order in which the turtles move, and when which algorithm is executed
        {
            for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
            {
                (turtles.get(i)).unDrawTurtle();
                (turtles.get(i)).update(1000);              
                hello.setText("X: " + (turtles.get(i)).getPositionX() + "    Y: " + (turtles.get(i)).getPositionY());                   
            }   

            for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
            {               
                (turtles.get(i)).cohesian(turtles); //MAKE BOIDS ATTRACT
            }   

            for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
            {               
                (turtles.get(i)).drawTurtle();  
            }                           

            for (int i = 0; i < turtles.size(); i++) //for each turtle, perform the set algorithm
            {
                (turtles.get(i)).wrapPosition((turtles.get(i)).getPositionX(), (turtles.get(i)).getPositionY()); 
            }   

            //Here we are making sure the turtles are on the screen                 

            Utils.pause(deltaTime/2);
        }   

以下是将海龟添加到ArrayList的按钮的代码:

addTurtleButton.addActionListener( new ActionListener()
        {
            public void actionPerformed(ActionEvent event) 
            {
                turtles.add(new RandomTurtleB(canvas, 400, 300, currentSpeed, 0));
            }
        } );

        removeTurtleButton.addActionListener( new ActionListener()
        {
            public void actionPerformed(ActionEvent event) 
            {
                turtles.remove(turtles.size() - 1);
                canvas.removeMostRecentLine();
                canvas.removeMostRecentLine();
                canvas.removeMostRecentLine();
                canvas.removeMostRecentLine();
            }
        } );

在另一个类中是内聚方法,即添加海龟/更改ArrayList的内容:

    public void cohesian(ArrayList<DynamicTurtle> turtles) 
    {
        double flockingDistanceLimit = 50;
        double numberOfFlockers = 0;
        double combinedX = 0;
        double combinedY = 0;
        double averageCombinedX;
        double averageCombinedY;
        //ouble moveToFlock; 
        //double turnToFlock;     
        double distanceToPotentialFlock;        

        for (DynamicTurtle t : turtles) //SCAN FOR ALL TURTLES
        {
            if(this.getPositionX() != t.getPositionX() && this.getPositionY() != t.getPositionY()) //MAKE SURE TURTLE ISNT SCANNING ITS SELF
            {
                distanceToPotentialFlock = Math.sqrt(Math.pow((this.getPositionX()-t.getPositionX()),2 ) + Math.pow((this.getPositionY()-this.getPositionY()),2)); //FIND DISTANCE TO TURTLE

                System.out.println("distanceToPotentialFlock: " + distanceToPotentialFlock); //PRINT TO SCREEN HOW FAR AWAY THE TURTLE IS

                if(distanceToPotentialFlock < flockingDistanceLimit) //MAKE SURE THE FOUND TURTLE IS WITHIN RANGE
                {
                    combinedX = combinedX + t.getPositionX(); //FIND SUMMATION OF X POSITIONS
                    combinedY = combinedY + t.getPositionY(); //FIND SUMMATION OF Y POSITIONS
                    numberOfFlockers++; //AS A FLOCKER HAS BEEN FOUND INCREMENT THE NUMBER OF FLOCKERS                  

                    System.out.println("distanceToPotentialFlock: " + distanceToPotentialFlock);
                    System.out.println("numberOfFlockers: " + numberOfFlockers);

                    if(numberOfFlockers > 0)
                    {                
                        averageCombinedX = (combinedX / numberOfFlockers); //FIND AVERAGE X POSITION
                        averageCombinedY = (combinedY / numberOfFlockers); //FIND AVERAGE Y POSITION 

                        System.out.println("XFLOCK: " + averageCombinedX + "YFLOCK: " + averageCombinedY);

                        double angleRad = Math.atan2(averageCombinedY, averageCombinedX);
                        double angleDeg = Math.toDegrees(angleRad);

                        // place in 0,360 range
                        if(angleDeg < 0)
                        {
                            angleDeg = 360 - (-angleDeg);
                        }

                        this.turn(angleDeg);
                        this.move(10);

                    }   
                }                   
            }
        } 

我非常感谢帮助我解决这个问题的任何帮助。问候,詹姆斯。

1 个答案:

答案 0 :(得分:0)

由于每次按下按钮时都要添加或删除主turtles列表,因此会出现并发修改异常。您应该花一些时间阅读Java中的Event Dispatch Threads

基本上,您实际上正在处理多线程应用程序,因为按钮的单击事件恰好在不同的线程上执行,并且将修改共享变量 - 当前不是线程的turtles列表 - 安全数据结构。

有关上下文,请参阅SO query。因此,这里的一个解决方案是使用类似CopyOnWriteArrayList的线程安全数据结构。

这会慢吗?我的猜测是否定的 - 因为在你的应用程序中,与添加或删除它们相比,花费了大量时间来迭代海龟列表。 This SO query详细说明了CopyOnWriteArrayList

的效果

希望这能帮助您解决问题。