-2

I am aware that this is a frequently asked question, but I am stuck on how to solve it with my code.

I have a button on my GUI that allows me to add extra "turtles" to the graphics window, this adds a turtle to an arraylist which is showing flocking behaviour, from a gameloop structure. How can i make it so i can add as many turtles as i wish without this error being shown?

The game loop is as follows:

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);
        }   

Here is the code for the button adding turtles to the 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();
            }
        } );

And in a different class is the cohesion method which is adding turtles/changing the contents of the 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);

                    }   
                }                   
            }
        } 

I would greatly appreciate any assisance in helping me solving this problem. Regards, James.

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
  • 1
    Cpuld you please post the error message complete... – ΦXocę 웃 Пepeúpa ツ Aug 01 '16 at 16:48
  • Here is the eorror message: – James Hornsby Aug 01 '16 at 16:57
  • Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) at Turtle.cohesian(Turtle.java:69) at TurtleProgram.gameLoop(TurtleProgram.java:124) at TurtleProgram.(TurtleProgram.java:107) at TurtleProgram.main(TurtleProgram.java:25) cheers! – James Hornsby Aug 01 '16 at 16:57
  • Why is your `gameLoop()` code using index loops (`for (int i = 0; i < turtles.size(); i++)`) instead of enhanced loops (`for (DynamicTurtle t : turtles)`)? Is it to prevent `ConcurrentModificationException`? If so, why not use the same solution in the `cohesian()` method? – Andreas Aug 01 '16 at 17:13

1 Answers1

0

You get a concurrent modification exception since you are adding or removing to the main turtles list each time a button is pressed. You should take some time to read Event Dispatch Threads in Java.

Basically, you are actually dealing with a multi-threading application since the click event of the button happens to execute on a different thread and would be modifying a shared variable - the turtles list which currently is not a thread-safe data structure.

Refer the SO query for some context. So one solution here would be to use a thread-safe data structure like CopyOnWriteArrayList.

Would this be slow? My guess would be no - since in your application a lot of time is spent in iterating over the turtles list compared to adding or removing them. This SO query gives a good description of the performance for CopyOnWriteArrayList

Hope this gives you a head start to solve your problem.

Community
  • 1
  • 1
Prahalad Deshpande
  • 4,709
  • 1
  • 20
  • 22
  • Thankyou so much! with a bit of research on the websites you link me and google, by importing "import java.util.concurrent.CopyOnWriteArrayList; " i was able to get it to work very fast! Regards, James. – James Hornsby Aug 02 '16 at 16:34
  • @JamesHornsby Great!! Please accept my answer if it has helped you solve your problem so that others can have a reference to it in the future :) – Prahalad Deshpande Aug 02 '16 at 18:16