2016-07-05 50 views
-2

我有下面的代碼崩潰:爪哇 - ConcurrentModificationException的多線程程序,設置是包裹着同步

private LocalBundle(Bundle b, Map<Bundle, LocalBundle> clonnedObjs) { 
    this(); 
    synchronized (b.getVariables()) { // b.getVariables() is Set 
     addFrom(b, clonnedObjs); 
    } 
} 

但addFrom我得到的崩潰:

private synchronized void addFrom(Bundle b, Map<Bundle, LocalBundle> clonnedObjs) { 
    Set<TaintedVariable> variablesOfBundle = b.getVariables(); 
    for(TaintedVariable v : variablesOfBundle) { 

異常消息:

Exception in thread "pool-4-thread-1" java.util.ConcurrentModificationException 
    at java.util.HashMap$HashIterator.nextNode(Unknown Source) 
    at java.util.HashMap$KeyIterator.next(Unknown Source) 
    at x.y.z.LocalBundle.addFrom(VisitedNodesWithBundle.java:198) 

有人知道它爲什麼會發生?我用synchronized (b.getVariables())包裝,但它看起來像兩個線程正在執行for(TaintedVariable v : variablesOfBundle)

+1

請在增強for循環內顯示代碼。 –

+1

「它看起來像兩個線程正在執行」不一定。您可以使用單個線程獲得'ConcurrentModificationException'。 –

+0

雖然使用同步,但可能有[ConcurrentModificationException]重複(http://stackoverflow.com/questions/1655362/concurrentmodificationexception-despite-using-synchronized) – Raedwald

回答

3

的是要記住的​​的是,它只能保證獨佔訪問,如果每個人都訪問共享資源也同步。

例如,你可以訪問共享變量同步:

synchronized (foo) { 
    foo.setBar(); 
} 

而且你可以認爲,你必須把它獨佔訪問。然而,有什麼可以阻止另一個線程只是做一些沒有​​塊:

foo.setBar(); // No synchronization first. 

從你的描述,這聽起來像這種情況的發生;儘管如此,你還沒有給出關於「流氓」線程在做什麼的細節。

如果簡單地將元素添加到組,你可以讓你設置同步,當你創建:

Collections.synchronizedSet(new HashSet<TaintedVariable>()); 

對set方法現在各個呼叫將被同步的,所以你將不再獲得CME。但是,請注意,每個方法調用都應用了同步:如果您進行了一系列調用(例如,如果設置爲包含foo,然後添加bar),則需要圍繞該邏輯的明確​​塊。

2

我不知道,原因是另一個線程。仔細查看javadoc這個例外情況。據說:

請注意,此異常並不總是表明一個對象已被不同的線程同時修改。如果單個線程發出違反對象合約的一系列方法調用,則該對象可能會拋出此異常。例如,如果一個線程在使用快速迭代器迭代集合的同時直接修改集合,迭代器將拋出此異常。

這意味着,如果您在迭代時嘗試修改集合,則可能會在單個線程中導致此類異常。

你要查出來,你的代碼是否試圖修改variablesOfBundle集合在這個for循環

for(TaintedVariable v : variablesOfBundle) 
+2

不一定在該循環中;這正是我懷疑它的地方。例如,代碼中可能會有另一個線程修改'b.getVariables()',而不首先嚐試同步它。 –

+0

@AndyTurner,看起來你是對的。它在另一個線程中被修改,但被另一個類中的另一個代碼修改(因爲在循環中沒有'variablesOfBundle'的任何修改) – Ivan