This discussion is archived
8 Replies Latest reply: Jun 21, 2007 9:53 AM by 807605 RSS

ConcurrentModificationException

807605 Newbie
Currently Being Moderated
Hello all,

I am getting a ConcurrentModificationException when trying to run my code, even though I am using a ListIterator when I am iterating and removing. I wrote some sample code to show you.
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main extends JPanel
{
     private Engine engine;
     
     public Main()
     {
          setBackground(Color.black);
          
          engine = new Engine();
          
          Thread t = new Thread(new Runnable()
          {
               public void run()
               {
                    while(true)
                    {
                         Random randNumGen = new Random();
                         if(randNumGen.nextInt(5) == 1)
                         {
                              engine.createDots(randNumGen.nextInt(20)+1);
                         }
                         
                         repaint();
                         
                         try
                         {
                              Thread.sleep(20);
                         }
                         catch(InterruptedException e)
                         {
                              e.printStackTrace();
                         }
                    }
               }
          });
          t.start();
     }
     
     public void paintComponent(Graphics g)
     {
          super.paintComponent(g);
          
          g.setColor(Color.white);
          g.drawString(engine.dots.size() + " dots", 15, 15);
          engine.draw(g);
     }
     
     public static void main(String[] args)
     {
          JFrame f = new JFrame("Test");
          f.setSize(500, 500);
          f.setLocationRelativeTo(null);
          f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          f.setContentPane(new Main());
          f.setVisible(true);
     }
}

/*=================================================*/

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Random;

public class Engine
{
     protected ArrayList<Dot> dots;
     private ListIterator<Dot> iterator;
     
     public Engine()
     {
          dots = new ArrayList<Dot>();
     }
     
     public void createDots(int num)
     {
          for(int i=0; i<num; i++)
          {
               Random randNumGen = new Random();
               int x = randNumGen.nextInt(500);
               int y = randNumGen.nextInt(500);
               Dot dot = new Dot(this, x, y);
               dots.add(dot);
          }
     }
     
     public void actOnDots()
     {
          iterator = dots.listIterator();
          while(iterator.hasNext())
          {
               Dot dot = iterator.next();
               dot.act();
          }
     }
     
     public void removeDot()
     {
          if(iterator == null)
          {
               System.err.println("Cannot remoce Dot.");
          }
          else
          {
               iterator.remove();
          }
     }
     
     public void draw(Graphics g)
     {
          for(Dot dot : dots)
          {
               dot.draw(g);
          }
     }
}

/*============================================*/

import java.awt.Graphics;
import java.util.Random;

public class Dot
{
     private Engine engine;
     private int xPos;
     private int yPos;
     
     public Dot(Engine e, int x, int y)
     {
          engine = e;
          xPos = x;
          yPos = y;
     }
     
     public void act()
     {
          Random randNumGen = new Random();
          if(randNumGen.nextInt(20) == 1)
          {
               engine.removeDot();
          }
     }
     
     public void draw(Graphics g)
     {
          g.fillOval(xPos, yPos, 4, 4);
     }
}
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
     at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
     at java.util.AbstractList$Itr.next(Unknown Source)
     at concurrencydemo.Engine.draw(Engine.java:54)
     at concurrencydemo.Main.paintComponent(Main.java:54)
     at javax.swing.JComponent.paint(Unknown Source)
     at javax.swing.JComponent.paintWithOffscreenBuffer(Unknown Source)
     at javax.swing.JComponent.paintDoubleBuffered(Unknown Source)
     at javax.swing.JComponent._paintImmediately(Unknown Source)
     at javax.swing.JComponent.paintImmediately(Unknown Source)
     at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
     at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
     at java.awt.event.InvocationEvent.dispatch(Unknown Source)
     at java.awt.EventQueue.dispatchEvent(Unknown Source)
     at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
     at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
     at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
     at java.awt.EventDispatchThread.run(Unknown Source)


I occasionally get another error that completely freezes my program. Does anyone know why this happens? Thank you for your help.
  • 1. Re: ConcurrentModificationException
    791266 Explorer
    Currently Being Moderated
    This part:

    for(Dot dot : dots)

    Creates an iterator over the dots list, and the dots list is modified while the for loop is iterating.

    Kaj
  • 2. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    I was afraid of that. :(
    Is there any way to prevent that from happening? Thanks again for the help.
  • 3. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    A list that is accessed using a iterator should not be modified in any other way than using the same iterator.

    Otherwise it throws the Exception.
  • 4. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    But how could I use the same iterator? If I use it in place of the for loop, won't it dusrupt the other method that is using it?
  • 5. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    Does anyone know how I can solve this?
  • 6. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    This happens in almost ALL games. I have to use it a total of 3 times in mine:

    SOLUTION:
    for(int i = 0; i < dots.size(); i++){
         Dot dot = dots.get(i);
         dot.UPDATE(); //Or something 
         if (dot.NEEDSCLEANUP())
                  dots.remove(i--);
    }
    SO:
    In your "removedot" method, DONT REMOVE TEH DOT FROM THE ARRAY: just set it's "needscleanup" boolean to TRUE. Also, make sure the line says "dots.remove( i -- ) so that after removing you go one unit back in your list

    It's a very elegant solution :P
  • 7. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    If all else fails, use the Iterator in the old-fashioned way, only with the new generics.
  • 8. Re: ConcurrentModificationException
    807605 Newbie
    Currently Being Moderated
    taifunbrowser,

    I tried your suggestion, but I still get the exception. Here's the new code.
    import java.awt.Color;
    import java.awt.Graphics;
    import java.util.Random;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    public class Main extends JPanel
    {
         private Engine engine;
         
         public Main()
         {
              setBackground(Color.black);
              
              engine = new Engine();
              
              Thread t = new Thread(new Runnable()
              {
                   public void run()
                   {
                        while(true)
                        {
                             Random randNumGen = new Random();
                             if(randNumGen.nextInt(5) == 1)
                             {
                                  engine.createDots(randNumGen.nextInt(2000)+1);
                             }
                             
                             engine.actOnDots();
                             
                             repaint();
                             
                             try
                             {
                                  Thread.sleep(20);
                             }
                             catch(InterruptedException e)
                             {
                                  e.printStackTrace();
                             }
                        }
                   }
              });
              t.start();
         }
         
         public void paintComponent(Graphics g)
         {
              super.paintComponent(g);
              
              g.setColor(Color.white);
              g.drawString(engine.dots.size() + " dots", 15, 15);
              engine.draw(g);
         }
         
         public static void main(String[] args)
         {
              JFrame f = new JFrame("Test");
              f.setSize(500, 500);
              f.setLocationRelativeTo(null);
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              f.setContentPane(new Main());
              f.setVisible(true);
         }
    }
    
    /*=====================================================*/
    
    import java.awt.Graphics;
    import java.util.ArrayList;
    import java.util.ListIterator;
    import java.util.Random;
    
    public class Engine
    {
         protected ArrayList<Dot> dots;
         
         public Engine()
         {
              dots = new ArrayList<Dot>();
         }
         
         public void createDots(int num)
         {
              for(int i=0; i<num; i++)
              {
                   Random randNumGen = new Random();
                   int x = randNumGen.nextInt(500);
                   int y = randNumGen.nextInt(500);
                   Dot dot = new Dot(x, y);
                   dots.add(dot);
              }
         }
         
         public void actOnDots()
         {
              /*
              ListIterator<Dot> iterator = dots.listIterator();
              while(iterator.hasNext())
              {
                   Dot dot = iterator.next();
                   dot.act();
                   
                   if(dot.shouldBeRemoved())
                   {
                        iterator.remove();
                   }
              }*/
              
              for(int i=0; i<dots.size(); i++)
              {
                   Dot dot = dots.get(i);
                   dot.act();
                   
                   if(dot.shouldBeRemoved())
                   {
                        dots.remove(i--);
                   }
              }
         }
         
         public void draw(Graphics g)
         {
              for(Dot dot : dots)
              {
                   dot.draw(g);
              }
         }
    }
    
    /*=====================================================*/
    
    import java.awt.Graphics;
    import java.util.Random;
    
    public class Dot
    {
         private int xPos;
         private int yPos;
         private boolean shouldBeRemoved = false;
         
         public Dot(int x, int y)
         {
              xPos = x;
              yPos = y;
         }
         
         public void act()
         {
              Random randNumGen = new Random();
              if(randNumGen.nextInt(20) == 1)
              {
                   shouldBeRemoved = true;
              }
         }
         
         public boolean shouldBeRemoved()
         {
              return shouldBeRemoved;
         }
         
         public void draw(Graphics g)
         {
              g.fillOval(xPos, yPos, 4, 4);
         }
    }
    Both the commented and uncommented section give me errors. Thanks again for the help.