What is java.util.ConcurrentModificationException

1

July 3, 2012 by huionn

In my application, there is a class with collection that will be accessed by multiple threads. So, I decided to fully understand what is the concurrent modification exception. Otherwise, the bug may only be discovered in production environment.

public class ConcurrentModification { private List list = new ArrayList(); public static void main(String[] args) { final ConcurrentModification cm = new ConcurrentModification();

Runnable adder = new Runnable() { @Override public void run() { for (int i = 0; i < 100; i++) { cm.list.add("" + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Runnable iter = new Runnable() { @Override public void run() { Iterator itr = cm.list.iterator(); while (itr.hasNext()) { System.out.println(itr.next()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread t1 = new Thread(adder, "adder"); t1.setDaemon(false); t1.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Thread t2 = new Thread(iter, "adder"); t2.setDaemon(false); t2.start(); } }

Above is a small program to demonstrate the effect of ConcurrentModificationException.

The output is:

Exception in thread “adder” java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at concurrent.ConcurrentModification$2.run(ConcurrentModification.java:36)
    at java.lang.Thread.run(Thread.java:662)

The short explanation is that the iterator is backed by the list. Modification to the list will cause the iterator in indeterministic state. In order to prevent this, the implementation will detect the modification and throw exception (fail-fast).

As far as I know, there are two methods to prevent this. Both methods depend on synchronized list through Collections.synchronizedList().

method 1: snap shot the list and return the snap shot iterator

method 2: perform iteration in a block synchronized with the list as lock

public class SafeConcurrentModification {
  private List list = Collections.synchronizedList(new ArrayList());
  public boolean add(String s) {
    return list.add(s);
  }
  public Iterator getIterator() {
    List snapShot = new ArrayList(list);
    return snapShot.iterator();
  }
  public void iterate(IterationExecutor executor) {
    synchronized (list) {
      executor.execute(list.iterator());
    }
  }
  public static void main(String[] args) {
    final SafeConcurrentModification cm = new SafeConcurrentModification();

    Runnable adder = new Runnable() {

      @Override
      public void run() {
        for (int i = 0; i < 100; i++) {
          cm.add("" + i);
          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    };
    Runnable iter = new Runnable() {
      @Override
      public void run() {
        Iterator itr = cm.getIterator();
        while (itr.hasNext()) {
          System.out.println(itr.next());
          try {
            Thread.sleep(100);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
      }
    };
    Runnable iter2 = new Runnable() {
      @Override
      public void run() {
        cm.iterate(new IterationExecutor() {
          public void execute(Iterator iter) {
            Iterator itr = cm.list.iterator();
            while (itr.hasNext()) {
              System.out.println(itr.next());
              try {
                Thread.sleep(100);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
          }
        });
      }
    };
    Thread t1 = new Thread(adder, "adder");
    t1.setDaemon(false);
    t1.start();
    try {
      Thread.sleep(500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    Thread t2 = new Thread(iter, "adder");
    t2.setDaemon(false);
    t2.start();    
    try {
      Thread.sleep(500);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    Thread t3 = new Thread(iter2, "adder2");
    t3.setDaemon(false);
    t3.start();
  }

  public interface IterationExecutor {
    public void execute(Iterator iter);
  }
}

Method 1 is more robust compared to method 2. Method 2 will cause performance issue if the iteration takes too long (as in the example) because it blocks other access to the list. However there is a serious drawback in method 1 – its Iterator.remove() does not work.


Fortunately, there is simpler and elegant solution to this common problem:

java.util.concurrent.ConcurrentLinkedQueue. As mentioned in its iterator() javadoc, “The returned iterator is a “weakly consistent” iterator that will never throw ConcurrentModificationException, and guarantees to traverse elements as they existed upon construction of the iterator, and may (but is not guaranteed to) reflect any modifications subsequent to construction.”

Advertisements

One thought on “What is java.util.ConcurrentModificationException

  1. stargazer jt says:

    bro… is very hard to understand… can u provide more example?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: