代码之家  ›  专栏  ›  技术社区  ›  Jon Gjengset

在Java中使用AdvAccess集合并发修改异常

  •  0
  • Jon Gjengset  · 技术社区  · 16 年前

    我刚刚被Java应用程序中的一个问题弄糊涂了。

    当我试图运行下面给出的代码时,Java在“如果(这个.Vr.St.Stur.GET(v)。addAll(输出)”)行上引发一个CONTRONTRORADIVICIORATION异常。

    考虑到这是一个完全单线程的应用程序,我觉得这很奇怪,而且我实际上并没有修改任何我正在循环的东西,就我所知?

    事实上,我唯一能看到的错误发生在AdDALL方法内部,但这不应该发生,因为我使用Java类库中的HashMap和Link KeListList.

    private Queue<Vertex> worklist = new LinkedList<Vertex> ( );
    protected Map<Vertex, Set<T>> vertexStore = new HashMap<Vertex, Set<T>> ( );
    
    // . . .
    
    while ( this.worklist.size ( ) > 0 ) {
            Vertex vertex = this.worklist.remove ( );
    
            Set<T> output = this.processVertice ( vertex, this.vertexStore.get ( vertex ) );
    
            this.vertexStore.put ( vertex, output );
    
            for ( Vertex v : vertex.edgesTo ( ) ) {
                // Conveniently, addAll returns true if the set changed
                if ( this.vertexStore.get ( v ).addAll ( output ) )
                    this.worklist.add ( v );
            }
        }
    

    编辑:错误跟踪:

    Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
        at java.util.HashMap$KeyIterator.next(HashMap.java:828)
        at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
        at DataFlowAnalyser.process(DataFlowAnalyser.java:41) (the if line)
    

    任何好主意都欢迎!

    完整来源 here (抱歉,没有评论,代码未完成)

    干杯, 乔恩

    2 回复  |  直到 16 年前
        1
  •  3
  •   Mike Deck    16 年前

    调用addall并传递对集合本身的引用。如果通过代码进行调试,您将看到this.vertexstore.get(v)返回与输出变量引用的对象相同的对象。

    通常,对于哈希集来说,这不是问题,因为如果您只是添加所有相同的元素,addall实际上不会修改哈希集的状态。然而,在本例中,您将在将HamiltonPath实例添加到集合后修改它们,从而更改它们的哈希代码,并使哈希集认为要添加的对象与它已经添加的对象不同。

    下面是一些比我的散文更好地说明问题的代码:

    List<String> list1 = Arrays.asList("foo");
    List<String> list2 = Arrays.asList("bar");
    Set<List<String>> set = new HashSet<List<String>>();
    set.add(list1);
    set.add(list2);
    list1.add("baz"); 
    list2.add("qux");
    set.addAll(set); // throws ConcurrentModificationException
    
        2
  •  -2
  •   punkers    16 年前

    您的代码会中断,因为您在迭代集合时修改集合,而Java不喜欢。如果要这样做,请使用使用使用与标准映射不同类型迭代器的ConcurrentHashMap。