Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Collections.sort() missing ConcurrentModificationException

I stumbled over this odd bug. Seems like Collections.sort() does not modify the sorted list in a way that enables a detection of concurrent modifications when also iterating over the same list. Example code:

    List<Integer> my_list = new ArrayList<Integer>();

    my_list.add(2);
    my_list.add(1);

    for (Integer num : my_list) {

        /*
         * print list
         */
        StringBuilder sb = new StringBuilder();
        for (Integer i : my_list)
            sb.append(i).append(",");
        System.out.println("List: " + sb.toString());

        /*
         * sort list
         */
        System.out.println("CurrentElement: " + num);
        Collections.sort(my_list);
    }

outputs

List: 2,1,
CurrentElement: 2
List: 1,2,
CurrentElement: 2

One would expect a ConcurrentModificationException, but it is not being raised and the code works although it shouldn't.

like image 734
Daniel Avatar asked Dec 11 '12 23:12

Daniel


1 Answers

Why would it throw ConcurrentModificationException when you are not adding/removing elements from your collection while iterating?

Note that ConcurrentModificationException would only occur when a new element is added in to your collection or remove from your collection while iterating. i.e., when your Collection is Structurally modified.

(Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)

sort wouldn't structurally modify your Collection, all it does is modify the order. Below code would throw ConcurrentModificationException as it add's an extra element into the collection while iterating.

for(Integer num : my_list) {
    my_list.add(12);
    }

If you look at the source of sort method in Collections class, its not throwing ConcurrentModificationException.

This implementation dumps the specified list into an array, sorts the array, and iterates over the list resetting each element from the corresponding position in the array. This avoids the n2 log(n) performance that would result from attempting to sort a linked list in place.

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();
        Arrays.sort(a);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

Extract from the book java Generics and Collections:

The policy of the iterators for the Java 2 collections is to fail fast, as described in Section 11.1: every time they access the backing collection, they check it for structural modification (which, in general, means that elements have been added or removed from the collection). If they detect structural modification, they fail immediately, throwing ConcurrentModificationException rather than continuing to attempt to iterate over the modified collection with unpredictable results.

like image 153
PermGenError Avatar answered Sep 28 '22 09:09

PermGenError