同步方法上的java ConcurrentModificationException
我正在处理很多来自TCPsocket的事件(每秒10个),所以我使用多线程处理这些事件
public class MainActivity extends Activity {
...
// In this Map I store the tab name and the associated TabHost.TabSpec instance
private static Map<String, TabHost.TabSpec> Tabs = Collections.synchronizedMap(new LinkedHashMap<String, TabHost.TabSpec>());
// In this Map I store pairs of tab-names and a HashSet of undelivered messages
// It's a class that extends Map<String, HashSet<String>> with some additional functions that doesn't have anything to do with Tabs.
private static NamesListing Names = Collections.synchronizedMap(new LinkedHashMap<String, HashSet<String>>());
// Yes, I know the names don't follow the Java standards, but I keeped them for mantaining the question coherence. I will change it in my code, though.
synchronized private static void ProcessEvent(final String name, final String message) {
// Low-priority thread
final Thread lowp = new Thread(
new Runnable() {
public void run() {
final Iterator<String> iter = Tabs.keySet().iterator();
while (iter.hasNext()) {
final String tabname = iter.next();
// This just returns an int making some calculations over the tabname
final int Status = Names.getUserStatus(tabname, message);
// Same than getUserStatus
if ((Names.isUserSpecial(Status)) && (name.equals(tabname))) {
// This just removes a line from the HashSet
Names.delLine(tabname, message);
}
}
}
});
lowp.setPriority(3);
lowp.start();
}
...
}
大多数情况下,这是正确的,但有时会出现这些事件的雪崩,有时我会得到一个ConcurrentModificationException:
12-10 14:08:42.071: E/AndroidRuntime(28135): FATAL EXCEPTION: Thread-369 12-10 14:08:42.071: E/AndroidRuntime(28135): java.util.ConcurrentModificationException 12-10 14:08:42.071: E/AndroidRuntime(28135): at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:347) 12-10 14:08:42.071: E/AndroidRuntime(28135): at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:367) 12-10 14:08:42.071: E/AndroidRuntime(28135): at es.irchispano.chat.MainActivity$6.run(MainActivity.java:244) 12-10 14:08:42.071: E/AndroidRuntime(28135): at java.lang.Thread.run(Thread.java:841)
注:244行对应于
final String tabname = iter.next();
声明
在我看来,这很奇怪,因为我使用的是一个系列。synchronizedMap和处理这些行的方法是同步的,那么为什么它仍然在发生呢
谢谢
------编辑------------
抱歉,最初的代码很简洁;我试图尽可能地简化,但显然这不是一个好主意。我正在粘贴实际代码。当然,这些结构中的每一个都已初始化(否则我就不会有问题了:-)),现在我将带着良心阅读您的所有评论,并发布我将发现的内容。谢谢大家的支持
# 1 楼答案
使用
Collections.synchronizedMap
只意味着多个线程可以同时调用get
/put
/delete
。它不能防止Collection
在Iterator
对其进行迭代时发生的错误。即使在单个线程中也可能发生这种情况,例如,如果映射中至少有3个元素(我认为),那么下面的线程应该抛出它:现在,正如其他人指出的那样,多个线程可以同时在
Map
上迭代,因为run
方法是不同步的。但是如果Tabs
没有被修改,那么这就不是错误的来源您还没有显示
Tabs
在哪里被修改这是因为在迭代器对其进行迭代时,映射正在被修改,导致了异常修复方法是对其进行迭代,并使用相同的锁对其进行修改
# 2 楼答案
对
Tabs
的访问不受任何锁的保护。有权访问Tabs
的runnable.run()
也不受任何锁的保护。您的代码允许并行生成多个线程。因为每个线程的runnable都可以访问映射(Tabs
),所以其中一个线程有可能在另一个线程迭代映射时修改该映射。这将导致您看到的ConcurrentModificationException