简体   繁体   中英

I can't figure out this ConcurrentModificationException

I was feeling my Java was rusty, so I tried a simple problem: a merge sort with Linked Lists that only returns unique values. Below was one of my first attempts. It made sense to me. The problem was, no matter what I did, I always got a ConcurrentModificationException .

Things I've tried include:

  • Making blocks or methods synchronized .
  • Replacing the LinkedLists with Iterators inside the sort method.
  • Keeping track of the size of the lists in separate variables (that part was left in).

Nothing worked. The ConcurrentModificationsException moved to other places but it remained in place. I'm really not sure why. How can I fix this?

In this particular attempt, the exception occurs at the call to addAll . I put all the operations on the lists inside their own block, but Java obviously doesn't care.

package com.regularoddity.dotcloud;

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

public class Merge {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<Integer> myList = new LinkedList<Integer>();
        myList.add(2);
        myList.add(9);
        myList.add(1);
        myList.add(3);
        myList.add(8);
        myList.add(7);
        myList.add(1);
        myList = sort(myList);
        Iterator<Integer> lit = myList.iterator();
        while(lit.hasNext()) System.out.printf("%s ", lit.next());
    }

    private static List<Integer> merge(List<Integer> list1, List<Integer> list2) {
        List<Integer> result = new LinkedList<Integer>();
        int size1 = list1.size();
        int size2 = list2.size();
        {
            while (size1 > 0 && size2 > 0) {
                if (list1.get(0) == list2.get(0)) {
                    result.add(list1.remove(0));
                    list2.remove(0);
                    size1--; size2--;
                }
                else if (list1.get(0) <= list2.get(0))
                {
                    result.add(list1.remove(0));
                    size1--;
                }
                else
                {
                    result.add(list2.remove(0));
                    size2--;
                }
            }
        }
        result.addAll(list1);
        result.addAll(list2);
        return result;
    }

    private static List<Integer> sort(List<Integer> list) {
        int lsize = list.size();
        if (lsize <= 1) return list;
        int pivot = lsize / 2;
        List<Integer> list1 = list.subList(0, pivot);
        List<Integer> list2 = list.subList(pivot, lsize);
        list1 = sort(list1);
        list2 = sort(list2);
        return merge(list1, list2);
    }


}

The thing that baffles me the most is that I never explicitly interate over the list. There must be an implicit iteration going on, but I don't seem to be able to factor it out.

EDIT: I didn't include the stacktrace because I (foolishly) thought that as it changed for every attempt at a fix, it would not be useful. But, really, it doesn't change much. Here's the stacktrace for the current implementation:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.SubList.checkForComodification(AbstractList.java:752)
    at java.util.SubList.size(AbstractList.java:625)
    at com.regularoddity.dotcloud.Merge.merge(Merge.java:30)
    at com.regularoddity.dotcloud.Merge.sort(Merge.java:64)
    at com.regularoddity.dotcloud.Merge.sort(Merge.java:62)
    at com.regularoddity.dotcloud.Merge.main(Merge.java:23)

com.regularoddity.dotcloud.Merge.main(Merge.java:23)

The javadoc of subList states:

The semantics of the list returned by this method become undefined if the backing list (ie, this list) is structurally modified in any way other than via the returned list.

In your case, you call subList twice and modify the original list via both sublists. That is the source of your exception.

Without changing too much your code, you could simply make copies to avoid that problem:

List<Integer> list1 = new LinkedList<> (list.subList(0, pivot));
List<Integer> list2 = new LinkedList<> (list.subList(pivot, lsize));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM