ccpizza
ccpizza

Reputation: 31801

Java example code for generating a ConcurrentModificationException

I am expecting the code below to throw a ConcurrentModificationException, but instead I am getting an ArrayIndexOutOfBoundsException.

I am aware that a ConcurrentModificationException is not guaranteed as per javadoc included below, but I am attempting to recreate a scenario that leads to ConcurrentModificationException in order to better understand the mechanism of concurrency errors.

From ArrayList javadoc:

Fail-fast iterators throw 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.

public class RaceConditions {

    private static final int NUM_THREADS = 1000;
    private static final int NUM_ELEMENTS = 10000;
    private List<Integer> list = new ArrayList<>();

    public static void main(String... args) {

        for (int i = 0; i < NUM_THREADS; i++) {
            final int fi = i;

            new Thread() {
                @Override
                public void run() {
                    for (int j = 0; j < NUM_ELEMENTS; j++) {
                        list.add(0, fi);
                    }
                }
            }.start();
        }

        System.out.println(list.size());
    }
}

My question is what would I need to modify in the code above in order to get a guaranteed (or almost guaranteed) ConcurrentModificationException?

Upvotes: 3

Views: 550

Answers (4)

Abhai
Abhai

Reputation: 1

This should help in generating the concurrentmodificationexception: Access element via iterator and also modifying list directly

List<String> data1 = new ArrayList();
        data1.add("A");
        data1.add("AB");
        data1.add("ABC");
        data1.add("ABCD");

        Iterator itr = data1.iterator();

        while (itr.hasNext()) {
            itr.next();
            System.out.println(itr.next());
            itr.remove();
            data1.add("E");
        }

Upvotes: 0

dimo414
dimo414

Reputation: 48874

Despite the name, a ConcurrentModificationException does not only occur in multi-threaded applications. Instead it usually indicates a collection was modified while you were iterating or otherwise interacting with the collection. As a RuntimeException, it generally indicates a programming error. If you don't misuse the collections you're working with, you should never see a CME.

The easiest way to generate one is to call .remove() from inside a for-each loop. This happens because the Iterator that the for-each loop is using is keeping track of where in the collection it is (e.g. for an ArrayList it's tracking the current index). If you modify the collection by calling .remove() the iterator's state is no longer consistent with the collection's state, and therefore the iterator will fail-fast by raising a CME if it's able to detect the inconsistency.

Here's an example:

  1. Construct an ArrayList containing [1, 2, 3, 4]
  2. Call .iterator() to get an Iterator of this list. Internally the Iterator will be pointed at index 0.
  3. Call .next() on the iterator, returning 1 and advancing the internal pointer to index 1.
  4. Call .remove(0) on the list, to remove the 0th element, 1, from the list, and shift the remaining elements forward one. Our list is now [2, 3, 4].
  5. Call .next() on the iterator. Since it's internal state points to index 1 it would return 3, skipping 2, which would be a problem. If possible the iterator will detect this inconsistency and fail, rather than silently continue erroneously.

All the collections in java.util do extra work to detect these inconsistencies and raise CMEs when possible, and most other popular collections (like Guava's) do so as well. But it's not possible to always detect these issues and so they can only promise a best-effort level of error-checking, which is why the Javadoc has to be somewhat vague.

Upvotes: 2

Tunaki
Tunaki

Reputation: 137269

You are misunderstanding this exception. From ConcurrentModificationException:

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it.

In your example, there is no iteration over the list so this exception can never be thrown.

Upvotes: 1

Marcinek
Marcinek

Reputation: 2117

This will give you always an ConcurrentModificationException

public class App {
    public static void main(String[] args) { 
        List<String> list = new ArrayList<>();

        list.add("Test");
        list.add("Test");
        list.add("Test");
        list.add("Test");
        list.add("Test");

        for(String item : list) {
            list.remove(item);
        }
    }
} 

This exception is thrown when ever you try to change a collection while you currently iterating over it.

Upvotes: 3

Related Questions