ConcurrentModificationException in ArrayList - Bug Reaper

                  Bug Reaper

Lean about Automation Testing,Selenium WebDriver,RestAssured,Appium,Jenkins,JAVA,API Automation,TestNG,Maven, Rest API, SOAP API,Linux,Maven,Security Testing,Interview Questions

Friday, 30 March 2018

ConcurrentModificationException in ArrayList

This generally comes when  use for each loop

Example
package mypackage;

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

public class my {

public static void main(String[] args) {

List<String> ls = new ArrayList<>();

ls.add("1");
ls.add("2");
ls.add("3");

for (String ok:ls) {
if (ok.equals("2")) {
ls.add("5");
ls.remove("5");
}
}

System.out.println(ls);
}
}


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 mypackage.my.main(my.java:16)


But it would run fine when we use normal For Loop

package mypackage;

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

public class my {

public static void main(String[] args) {

List<String> ls = new ArrayList<>();

ls.add("1");
ls.add("2");
ls.add("3");

for (int i = 0; i < ls.size(); i++) {
if (ls.get(i).equals("2")) {
ls.add("5");
ls.remove("5");
}
}

System.out.println(ls);
}
}

Output

[1, 2, 3]


Synchronization of ArrayList in Java

Implementation of arrayList is not synchronized is by default. It means if a thread modifies it structurally and multiple threads access it concurrently, it must be synchronized externally.

1. Why are almost collection classes not thread-safe?

Do you notice that all the basic collection classes - ArrayList, LinkedList, HashMap, HashSet, TreeMap, TreeSet, etc - all are not synchronized? In fact, all collection classes (except Vector and Hashtable) in the java.util package are not thread-safe.

The only two legacy collections are thread-safe: Vector and Hashtable. WHY?

Here’s the reason: Synchronization can be very expensive!

Vector and Hashtable quickly expose poor performance in multi-threaded programs. As you may know, synchronization requires locks which always take time to monitor, and that reduces the performance.

That’s why the new collections (List, Set, Map, etc) provide no concurrency control at all to provide maximum performance in single-threaded applications.


How Does Concurrent Modification Occurs in Multi Threading 

public class IteratorFailFastTest {


    private List<Integer> list = new ArrayList<>();

//Constructor to make multiple adds in list using for loop

    public IteratorFailFastTest() {

        for (int i = 0; i < 10_000; i++) {

            list.add(i); // adding elements here

        }

    }

 

    public void runUpdateThread() {

        Thread thread1 = new Thread(new Runnable() {

            public void run() {

                for (int i = 10_000; i < 20_000; i++) {

                    list.add(i); // adding elements here

                }

            }

        });

        thread1.start();

    }

 

    public void runIteratorThread() {

        Thread thread2 = new Thread(new Runnable() {

            public void run() {

                ListIterator<Integer> iterator = list.listIterator();

                while (iterator.hasNext()) {

                    Integer number = iterator.next();

                    System.out.println(number);

                }

            }

        }); 

        thread2.start();

    }

 

    public static void main(String[] args) {

        IteratorFailFastTest tester = new IteratorFailFastTest();

        tester.runIteratorThread(); // adding

        tester.runUpdateThread(); //iterating

    }

}


Note:
As you can see, the thread1 is iterating the list, while the thread2 adds more elements to the collection. This causes the ConcurrentModificationException to be thrown.

Solution

There are two way to create Synchronized Arraylist.

1. Collections.synchronizedList() method.

2. Using CopyOnWriteArrayList.

Example
Collections.synchronizedList() method.

public class my {

public static void main(String[] args) {

List<String> ls=Collections.synchronizedList(new ArrayList<String>());

ls.add("Name");

ls.add("Hello");

ls.add("Hi");

ls.add("Cool");

ls.add("Good");

synchronized (ls)

{

Iterator<String> iterator = ls.iterator();

while (iterator.hasNext()) {

String next = iterator.next();

System.out.println(next);

}

}

}

}


When using the iterator of a synchronized collection, we should use synchronized block to safeguard the iteration code because the iterator itself is not thread-safe.

Example

Using CopyOnWriteArrayList.

It achieves thread-safety by creating a separate copy of List 

It is costly as involves separate Array copy with every write operation(e.g. add, set, remove..)

It is very efficient when you have List and need to traverse over its elements and don’t modify often it.

Iterator does not throw ConcurrentModificationException even if copyOnWriteArrayList is modified once iterator is created because iterator is iterating over the separate copy of ArrayList while write operation is happening on another copy of ArrayList.

public static void main (String[] args)

    {

        // creating a thread-safe Arraylist.

        CopyOnWriteArrayList<String> threadSafeList

            = new CopyOnWriteArrayList<String>();

        // Adding elements to synchronized ArrayList

        threadSafeList.add("geek");

        threadSafeList.add("code");

        threadSafeList.add("practice");

        System.out.println("Elements of synchronized ArrayList :");

        // Iterating on the synchronized ArrayList using iterator.

        Iterator<String> it = threadSafeList.iterator();

        while (it.hasNext())

            System.out.println(it.next());

    }


Good Reads
http://www.codejava.net/java-core/concurrency/java-concurrent-collection-copyonwritearraylist-examples

https://www.geeksforgeeks.org/synchronization-arraylist-java/

https://www.quora.com/in/How-do-I-make-Arraylist-threadsafe

 ConcurrentHashMap

  • You should use ConcurrentHashMap when you need very high concurrency in your project.
  • It is thread safe without synchronizing the whole map.
  • Reads can happen very fast

No comments:

Post a Comment