DEV Community

Manish Thakurani for CodeGreen

Posted on

In Java what is ConcurrentModificationException? How to avoid it in multi-threading. #InterviewQuestion

Problem Statement:

In multi-threaded environments, when multiple threads interact with the same object or collection concurrently, there is a risk of ConcurrentModificationException due to unsynchronized modifications.

Background

ConcurrentModificationException is thrown by List in Java when the collection is structurally modified (e.g., adding or removing elements) during iteration. This is due to the modification count maintained internally by the list, which is checked by iterators to detect concurrent modifications. If the modification count changes unexpectedly, it signals that the collection's structure has been altered concurrently, ensuring safe and consistent iteration behavior.

Solution:

Ensure thread safety by using synchronized blocks or concurrent data structures to manage access and modifications to shared objects or collections.

1. Java ConcurrentModificationException (Without Synchronization)

Example demonstrating ConcurrentModificationException when modifying a collection concurrently without proper synchronization.

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

public class ConcurrentModificationExample{
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        // Thread 1: Iterating and modifying the list
        Thread thread1 = new Thread(() -> {
            Iterator<Integer> iterator = numbers.iterator();
            while (iterator.hasNext()) {
                Integer number = iterator.next();
                System.out.println("Thread 1::value=>"+number);

            }
        });

        // Thread 2: Adding an element to the list concurrently
        Thread thread2 = new Thread(() -> {
            try {
                numbers.add(4);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();


        System.out.println("List after modification: " + numbers);
    }
}

/*
Output:
Exception in thread "Thread-0" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1043)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:997)
    at ConcurrentModificationExample.lambda$main$0(ConcurrentModificationExample.java:16)
    at java.base/java.lang.Thread.run(Thread.java:829)
*/
Enter fullscreen mode Exit fullscreen mode

2. Java ConcurrentModificationException Avoided (With Synchronization)

Example demonstrating how to avoid ConcurrentModificationException by using proper synchronization.


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

public class ConcurrentModificationExample {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        // Thread 1: Iterating and removing elements with proper synchronization
        Thread thread1 = new Thread(() -> {
            synchronized (numbers) {
                Iterator<Integer> iterator = numbers.iterator();
                while (iterator.hasNext()) {
                    Integer number = iterator.next();
                    System.out.println("Thread 1::value=>"+number);

                }
            }
        });

        // Thread 2: Adding an element to the list concurrently
        Thread thread2 = new Thread(() -> {
            synchronized (numbers) {
                    numbers.add(4);

            }
        });

        thread1.start();
        thread2.start();

        System.out.println("List after modification: " + numbers);
    }
}
/*Output:
Thread 1::value=>1
Thread 1::value=>2
Thread 1::value=>3
List after modification: [1, 2, 3, 4]
*/
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • ConcurrentModificationException Example: The first example demonstrates a scenario where Thread 1 attempts to iterate over element s from the list while Thread 2 adds an element concurrently, leading to ConcurrentModificationException due to lack of synchronization.

  • ConcurrentModificationException Avoided Example: The second example shows how to avoid ConcurrentModificationException by using synchronized blocks around critical sections of code where the list is being iterated or modified. This ensures that only one thread accesses the list at a time, preventing concurrent modification issues.

Conclusion:

Implementing proper synchronization techniques such as using synchronized blocks or concurrent data structures from java.util.concurrent package is essential when working with shared mutable data structures in multi-threaded environments. This ensures thread safety and prevents runtime errors like ConcurrentModificationException in Java programs.

Top comments (0)