2011-07-07 34 views
2

編輯:好吧,我覺得很羞怯。我在看錯誤的構造函數。根據Kal的回答,被調用的真正構造函數(見下文)違反了foreach循環的併發規則。ConcurrentModificationException對單線程代碼

謝謝你的幫助不管!它仍然可以幫助我修復代碼中的實際錯誤。

所有

我是一個相當新的Java程序員,和我纔剛剛開始獲得的語言基本手柄。我目前正在與對話參與者系統合作,但首先試圖讓我們的系統對邏輯術語的表示達到規範。我幾乎完成,但遇到了以下錯誤:

Exception in thread "main" java.util.ConcurrentModificationException 
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) 
at java.util.AbstractList$Itr.next(AbstractList.java:343) 
at com.Term.<init>(Term.java:97) 
at com.Term.substituteVariables(Term.java:251) 
at com.Term.substituteVariables(Term.java:247) 
at com.Term.substituteVariables(Term.java:247) 
at com.TermPredTestArch.main(TermPredTestArch.java:40) 

問題,substituteVariables的方法,基本上是拷貝構造函數,有輕微的修改:它需要在地圖上的綁定,並遞歸迭代通過它從中調用的術語對象,沿途找到變量並將它們交換出來用於實例化。奇怪的是,當我離開的時候(雖然我沒有廣泛測試),它似乎只是在昨天晚上才工作,但現在拒絕演奏很好;我沒有做出實質性的修改。

相關的代碼如下(行232-252):

232 /** Returns a new Term with the appropriate bindings substituted */ 
233 public Term substituteVariables(Map<Variable, Symbol> bindings) { 
234 ArrayList<Symbol> args = this.getArgs(); 
235 ArrayList<Symbol> newArgs = new ArrayList<Symbol>(); 
236 Set<Variable> vars  = this.getVars(); 
237 Set<Variable> bindingKeys = bindings.keySet(); 
238 for(Symbol s: args) { 
239  // if s is a Variable, check to see if it has a substituion, and 
240  // if so, swap it out 
241  if(s instanceof Variable) { 
242  if(bindingKeys.contains(s)) newArgs.add(bindings.get(s)); 
243  else      newArgs.add(s); 
244  // if s is a Term, add it and recursively substitute any variables 
245  // it has within the current set of bindings 
246  } else if(s instanceof Term) { 
247  newArgs.add(((Term) s).substituteVariables(bindings)); 
248  // if s is just a symbol, simply add it to the args 
249  } else newArgs.add(s); 
250 } 
251 return new Term(this.getName(), newArgs); 
252 } 

編輯:這裏是爲期限的構造:

public Term(String n, ArrayList<Symbol> a) { 
    super(n); 
    args = a; 
    HashSet<Variable> varsToAdd = new HashSet<Variable>(); 
    for(Symbol s: a) parseArg(s.toString()); 
}   

這是-actual-構造,這是被稱爲,而不是我認爲被稱爲的那個。根據Kal的回答,事實上,這違反了foreach循環併發規則。

從我已經完成的研究中,我知道ConcurrentModificationException通常是由多個線程在沒有同步的情況下同時迭代/修改一個Collection引起的,但我沒有故意的並行性,也沒有任何其他地方的類或測試使用它的代碼。否則,我不完全確定。該類的javadoc提到它也可能是迭代器同時迭代和修改一個Collection的原因,但我不認爲我也這麼做;我只是觀察迭代的Collection並使用它的信息來構建另一個Collection。這是否違反併發規定?

任何你可能能夠提供的指針將非常感謝!我也會爲任何嚴重違反Java禮節或風格的行爲先發制人地道歉(請隨時指出這些行爲!)。

感謝,當你同時通過它使用了迭代循環修改一個ArrayList發生

+0

我認爲你需要顯示的期限構造,因爲那正是把它扔。 – Anon

+0

「Term」的構造函數是什麼樣的?這就是拋出異常的地方。 –

+0

加入;謝謝 –

回答

11

ConcurrentModificationException的。

正確執行此操作的方法是使用Iterator添加/刪除方法。

下面是來自API的相關文件 -

此類的iterator和listIterator方法返回的迭代器是快速失敗的:在如果名單在任何時間從結構上修改創建迭代器之後,除了通過迭代器自己的刪除或添加方法以外的任何方式,迭代器將拋出ConcurrentModificationException。因此,面對併發修改,迭代器快速而乾淨地失敗,而不是在將來某個未確定的時間冒着任意的,非確定性的行爲風險。

+0

['Iterator'](http://download.oracle.com/javase/6/docs/api/java/util/Iterator.html)doesn沒有'add(...)'方法,儘管['ListIterator'](http://download.oracle.com/javase/6/docs/api/java/util/ListIterator.html)。 – mre

+0

@bunny - 有效的點。我將編輯我的帖子。 – Kal

0
newArgs.add(((Term) s).substituteVariables(bindings)); 

所以在這部分代碼中,你會得到你的錯誤;像Kal說的那樣,當你編輯你正在迭代的ArrayList時就會發生這種情況。要解決此問題更改

for(Symbol s: args) { 

for (int i = 0; i < args.size(); i++) { 
    Symbol s = args.get(i); 
+1

*多線程使用警告*:如果您沒有通過正確同步修復根本原因,您最終會遇到其他類型的問題。例如。 'args.get(i)'如果在'args.size()'和'args.get()'之間調用'ArrayList.clear()',''會返回null。您提供的代碼僅適用於單線程。 – Matthieu