ConcurrentModificationException - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Monday, July 18, 2016

ConcurrentModificationException

What is Concurrent Modification?

When one or more thread iterating over collection. One thread modify the collection( either adding the element, removing the element, or updating the element to collection object) is known as Concurrent Modification.

Fail Fast Iterator

Fail fast iterator, while iterating over collection instantly throws concurrent modification exception if there is modification in collection object. It fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undermined time in the future.

Fail-fast iterator can throw ConcurrentMoficationException in two scenario.

1.Single Threaded Environment:

After creation of iterator on collection, collection is modified any time by any method except iterator remove() method.

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class FailFastDemo {
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("Santosh");
    list.add("Mohan");
    list.add("Satyam");
    list.add("Shivam");

    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String value = iterator.next();
      System.out.println(value);
      iterator.remove();
    }
    System.out.println("List Size: " + list.size());
  }
}

Output of above program:

Santosh
Mohan
Satyam
Shivam
List Size: 0

In above example we are modifying the collection object , but we are removing the element from collection object using iterator's remove() method,that's why we did not get concurrent modification exception.

2.Multi-threaded environment:

If one thread modifying the collection while other thread is iterating over it.

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

java.util.ConcurrentModificationException

Lets see concurrent modification exception scenario with examples:


Example 1 using ArrayList

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class FailFastDemo {
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("Santosh");
    list.add("Mohan");
    list.add("Satyam");
    list.add("Shivam");

    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
      String value = iterator.next();
      System.out.println(value);
      if (value.equals("Mohan")) list.remove(value);
    }
    System.out.println("List Size: " + list.size());
  }
}

Above program will throws java.util.ConcurrentModificationException when run it. As shown in below output console.

Santosh
Mohan
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 com.concurrent.FailFastDemo.main(FailFastDemo.java:17)

From above output stack trace, it is clear that concurrent modification exception throws when iterator next() function called.

How fail-fast iterator internally works?

ArrayList class implements AbstractList class where an int variable modCount is defined. This field is used by the iterator and list iterator implementation returned by the iterator and listIterator methods.If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or add operations. This provides fail-fast behavior, rather than non-deterministic behavior in the face of concurrent modification during iteration.

In HashMap class modCount filed is defined like transient int modCount;.This field is used by iterator to count number of times this HashMap has been structurally modified.Structural modifications are those, that change the number of mappings in the HashMap or otherwise modify its internal structure (e.g.,rehash). This field is used to make iterators on Collection-views of the HashMap fail-fast.

Example 2 using HashTable

package com.walkingtechie.concurrent;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;

public class FailFastExample {

 public static void main(String[] args) {
  Map<Integer, String> map = new Hashtable<Integer, String>();
  map.put(1, "Santosh");
  map.put(2, "Mohan");
  map.put(3, "Satyam");
  map.put(4, "Shivam");

  Iterator<Integer> iterator = map.keySet().iterator();
  while (iterator.hasNext()) {
   int key = iterator.next();
   System.out.println(map.get(key));
   map.put(5, "Shankar");
  }
 }
}

Above program will throws java.util.ConcurrentModificationException when run it. As shown in below output console.

Shivam
Exception in thread "main" java.util.ConcurrentModificationException
 at java.util.Hashtable$Enumerator.next(Hashtable.java:1367)
 at com.concurrent.FailFastExample.main(FailFastExample.java:18)

To Avoid ConcurrentModificationException in multi-threaded environment

  1. Convert the list into array and then iterate on the array.This will not work well for long list because it will affect performance.
  2. You can lock the list while iterating by putting it in a synchronized block. This approach is not recommended because it will cease the benefits of multithreading.
  3. If you are using JDK1.5 or higher then you can use ConcurrentHashMap and CopyOnWriteArrayList classes. This is the recommended approach to avoid concurrent modification exception.

To Avoid ConcurrentModificationException in single-threaded environment

You can use the iterator remove() function to remove the object from underlying collection object.

Now Lets understand Concurrent Collection classes:

Method 1 using CopyOnWriteArrayList

package com.walkingtechie.concurrent;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class TheadSafeIteratorDemo {
 public static void main(String[] args) {
  List<String> list = new CopyOnWriteArrayList<String>();
  list.add("Santosh");
  list.add("Mohan");
  list.add("Satyam");
  list.add("Shivam");

  Iterator<String> iterator = list.iterator();
  while (iterator.hasNext()) {
   String value = iterator.next();
   System.out.println(value);
   if (value.equals("Mohan")) {
    list.remove("Mohan");
    list.add("Niraj");
    list.add("Amit");
   }
  }
  System.out.println("List Size: " + list.size());
 }
}

Output of the above program shown below.You can see that there is no ConcurrentModificationException being thrown by the program.

Santosh
Mohan
Satyam
Shivam
List Size: 5

Method 2 using ConcurrentHashMap

package com.walkingtechie.concurrent;

import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public final class ThreadSafeIteratorExample {

 public static void main(String[] args) {
  Map<Integer, String> map = new ConcurrentHashMap<Integer, String>();
  map.put(1, "Santosh");
  map.put(2, "Mohan");
  map.put(3, "Satyam");
  map.put(4, "Shivam");

  Iterator<Integer> iterator = map.keySet().iterator();
  while (iterator.hasNext()) {
   int key = iterator.next();
   System.out.println(map.get(key));
   if (key == 3) {
    map.put(5, "Shankar");
    map.put(6, "Amit");
   }
  }
  System.out.println("Map size: " + map.size());
 }
}

Output of the above program shown below.You can see that there is no ConcurrentModificationException being thrown by the program.

Santosh
Mohan
Satyam
Shivam
Shankar
Amit
Map size: 6

ConcurrentModificationException is most darling question from interview perspective. I suggest to read this exception before going to attain interview.

No comments :

Post a Comment