2016-07-05 49 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