我对Java应用程序中遇到的一个问题感到非常困惑。
当我尝试运行下面给出的代码时,Java会在“if(this.vertexStore.get(v).addAll(output))”行上引发ConcurrentModificationException。
我觉得这很奇怪,考虑到这是一个完全单线程的应用程序,并且我实际上并没有修改我正在循环的任何东西,据我所知?
事实上,我能看到错误发生的唯一地方是在addAll方法中,但这不应该发生,因为我正在使用Java类库中的HashMap和LinkedList ...
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)
非常欢迎任何好的想法!
PS:完整来源here(抱歉缺少评论,代码未完成)
干杯, 乔恩
答案 0 :(得分:3)
您正在调用addAll并将引用传递给Set本身。如果通过代码进行调试,您将看到this.vertexStore.get(v)返回与输出var引用的对象相同的对象。
通常这对于HashSet来说不是问题,因为如果你只是添加所有相同的元素,addAll实际上不会修改HashSet的状态。但是,在这种情况下,您将在将HamiltonPath的实例添加到集合后修改它们的实例,而后者又会更改其哈希代码,并使HashSet认为添加的对象与已有的对象不同。
这里有一些代码可以比我的散文更好地说明问题:
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
答案 1 :(得分:-2)
你的代码中断了,因为你正在修改一个集合,而你正在迭代它而java不喜欢它。如果你想这样做,请使用一个使用与标准地图不同类型的迭代器的ConcurrentHashMap。