5

The following function walks recursively through a list and divide it always by half and do something with the sublists. The recursion breaks when the listsize is 2. I know a concurrent modification exception occurs if I change the list when I iterate over it. But I don't use iterations and it still happens:

    private static List<ParticipantSlot> divide(List<ParticipantSlot> list) {
        int n = list.size();

        //do something 

        if (n>2){
            List<ParticipantSlot> l = divide(list.subList(0, n/2-1));
            List<ParticipantSlot> r= divide(list.subList(n/2, n));

            l.addAll(r);
            return l;
        }else{
            return list;
        }
    }
Anthea
  • 3,741
  • 5
  • 40
  • 64

3 Answers3

10

You're using addAll() which will iterate over the collection you provide in the argument. Now subList only returns a view onto the original list, so you're trying to add values onto a view of the original list, and iterate over a different part of the original list at the same time. Bang.

If you created a copy of the sublist each time, it should work - although it'll be pretty inefficient.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

You get a concurrent modification exception because sublist is backed by the original list:

The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list.

If you would like to avoid an exception, make a copy of the first sublist before modifying it.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Still, precisely how does the concurrent modification exception get thrown? – Mike Nakis Jan 05 '12 at 15:54
  • @MikeNakis call to `l.addAll(r)` modifies `list` indirectly through its "view" obtained by calling `sublist`. – Sergey Kalinichenko Jan 05 '12 at 15:59
  • Please excuse me if I am having a blonde moment, but... modifies it concurrently to what? I do not see any iteration or anything else happening concurrently on the list. Or are you saying that by design, any modification on a list is bound to result in a "concurrent modification" exception if a sublist has been created out of it and not GCd yet? That would be kind of odd, because it would mean that once I have taken a sublist I can never modify the original list, because I have no guarantee as to when or if the sublist will ever be GCd. – Mike Nakis Jan 05 '12 at 16:06
  • @MikeNakis "modifies it concurrently to what?" It modifies the list concurrently to accessing a portion of it through a sublist. In general, this makes sublist invalid, because the data "shifts" in the window, gets into the window, or disappears from it. Only sublists through which you read the original list matter: it's OK to keep a sublist after modifying the "base" list, even if the sublist has not become eligible for GC, as long as you no longer access the base list through it. Concurrent modification errors are detected on reads, not on writes. – Sergey Kalinichenko Jan 10 '12 at 23:33
3

If you are using ArrayList, you may want to change it to a CopyOnWriteArrayList, or ConcurrentLinkedQueue.

If you are on a Multi-thread environment, you will want to put a synchronized around your Array.

Hope it helps.

caarlos0
  • 20,020
  • 27
  • 85
  • 160