简体   繁体   English

我无法弄清楚这个ConcurrentModificationException

[英]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. 我觉得我的Java生锈了,所以我尝试了一个简单的问题:使用Linked Lists进行合并排序,只返回唯一值。 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 . 问题是,无论我做了什么,我总是得到一个ConcurrentModificationException

Things I've tried include: 我尝试过的事情包括:

  • Making blocks or methods synchronized . 使块或方法synchronized
  • Replacing the LinkedLists with Iterators inside the sort method. sort方法中的迭代器替换LinkedLists。
  • 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. ConcurrentModificationsException移动到其他地方但它仍然存在。 I'm really not sure why. 我真的不确定为什么。 How can I fix this? 我怎样才能解决这个问题?

In this particular attempt, the exception occurs at the call to addAll . 在此特定尝试中,在调用addAll时发生异常。 I put all the operations on the lists inside their own block, but Java obviously doesn't care. 我将列表中的所有操作都放在了自己的块中,但Java显然并不关心。

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) com.regularoddity.dotcloud.Merge.main(Merge.java:23)

The javadoc of subList states: 的javadoc的subList指出:

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. 在您的情况下,您调用subList两次并通过两个子列表修改原始列表。 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));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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