我在以下代码中崩溃了:
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)
答案 0 :(得分:3)
关于synchronized
要记住的事情是,如果访问共享资源的每个人也同步,它只保证独占访问。
例如,您可以同步对共享变量的访问:
synchronized (foo) {
foo.setBar();
}
您可以认为您拥有对它的独占访问权。但是,没有任何东西可以阻止另一个线程在没有synchronized
块的情况下执行某些操作:
foo.setBar(); // No synchronization first.
根据你的描述,听起来似乎正在发生;但是,你没有提供“流氓”线程正在做什么的任何细节。
如果只是在集合中添加元素,则可以在创建集合时使集合同步:
Collections.synchronizedSet(new HashSet<TaintedVariable>());
现在,对该集上方法的单独调用将被同步,因此您将不再获得CME。但请注意,同步应用每个方法调用:如果您进行一系列调用(例如,如果set包含foo
然后添加bar
),则需要明确synchronized
阻止了这种逻辑。
答案 1 :(得分:2)
我不确定,原因是另一个主题。仔细查看javadoc此异常。它说:
请注意,此异常并不总是表示某个对象已被另一个线程同时修改。如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此异常。例如,如果线程在使用失败快速迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。
这意味着,如果您在迭代时尝试修改集合,则可能会在单个线程中导致此类异常。
您必须检查代码是否尝试修改此for循环中的variablesOfBundle
集合
for(TaintedVariable v : variablesOfBundle)