Search code examples
javajava.util.concurrentthreadpoolexecutor

Why this code does not trigger ConcurrentModificationException?


I'm modifying same list from multiple threads, shouldn't it trigger ConcurrentModificationException while iterating list?

What could be done to trigger this exception?

public class ConcurrentTest {

    static List<String> list = setupList();

    public static List<String> setupList() {
        System.out.println("setup predefined list");

        List<String> l = new ArrayList();
        for(int i = 0; i < 50;i++) {
            l.add("test" + i);
        }

        return l;
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(50);

        for(int i = 0; i < 50; i++) {
            executorService.submit( () -> {     
                list.add("key1");       

                Thread currentThread = Thread.currentThread();
                System.out.println( Thread.currentThread().getName() + ", " + list.size() );

                for(String val: list) {
                    try {
                        Thread.sleep(25);
                    }
                    catch(Exception e) {

                    }
                }

            });
        }

        executorService.shutdown();
    }
}

Solution

  • Your code does (and can) produce a ConcurrentModificationException. You are not catching it to print it.

    With the below, we can see that it indeed throws many ConcurrentModificationException.

    try {
        for (String val : list) {
            try {
              Thread.sleep(25);
            } catch (Exception e) {
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    NOTE: From the javadoc,

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

    Also see: java.util.ConcurrentModificationException not thrown when expected


    Or, you could get the returned Future and collect them in a list. By doing that, you will get the exception when calling get on (atleast) one of the futures.