我在方法中有以下代码(Utils.currentPrinters是一个静态JsonObject):
JsonObject printers = Utils.currentPrinters;
for (Map.Entry<String, ?> entry : Utils.currentPrinters.entrySet()) {
String key = entry.getKey();
JsonObject printer = (JsonObject) entry.getValue();
if (...) {
printers.remove(key);
}
}
Utils.currentPrinters = printers;
有两个线程实际上调用此方法。如果它只是一个,那就完全没有问题了。但是在使用两个线程运行几秒后,它会崩溃并出现以下异常:
05-13 12:01:43.168 5739-5739/com.wasp.pos.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.util.ConcurrentModificationException
at com.google.gson.internal.LinkedTreeMap$LinkedTreeMapIterator.nextNode(LinkedTreeMap.java:541)
at com.google.gson.internal.LinkedTreeMap$EntrySet$1.next(LinkedTreeMap.java:565)
at com.google.gson.internal.LinkedTreeMap$EntrySet$1.next(LinkedTreeMap.java:563)
at com.wasp.pos.app.server.PrintersFinder.clearPrinters(PrintersFinder.java:184)
at com.wasp.pos.app.server.PrintersFinder.access$000(PrintersFinder.java:30)
at com.wasp.pos.app.server.PrintersFinder$1UpdateListThread.run(PrintersFinder.java:124)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:153)
at android.app.ActivityThread.main(ActivityThread.java:4987)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
at dalvik.system.NativeStart.main(Native Method)
我无法找到解决此问题的任何内容,ConcurrentMap或synchronized(打印机)没有修复它。请帮忙。
答案 0 :(得分:2)
在对它们进行迭代(printers.remove(key);
)时,无法从集合中删除(for (Map.Entry<String, ?> entry : Utils.currentPrinters.entrySet())
)项。
实现目标的最佳方法是收集您要删除的所有项目的列表,并在最后删除它们。
List<String> remove = new ArrayList<String>();
for (Map.Entry<String, ?> entry : Utils.currentPrinters.entrySet()) {
String key = entry.getKey();
if (...) {
remove.add(key);
}
}
// Remove the ones I don't want.
for(String r:remove) {
printers.remove(r);
}
完成后,您仍然需要使用synchronized
或ConcurrentMap
。
答案 1 :(得分:2)
如上所述,请勿从正在迭代的集合中删除。代替:
Set<String> removed = new TreeSet<String>();
for (Map.Entry<String, ?> entry : Utils.currentPrinters.entrySet()) {
String key = entry.getKey();
JsonObject printer = (JsonObject) entry.getValue();
if (...) {
removed.add(key);
}
}
for (String key : removed)
Utils.currentPrinters.remove(key);
另外两件事:
原始代码中的临时变量“printers”没有任何变化,因为它引用了同一个对象。除非出于某种原因,代码对你来说更清楚......
如果多个线程访问此方法......不要!他们正在做同样的事情,你将从中获益。同步整个块。
答案 2 :(得分:2)
我建议您使用Iterator,它允许您在迭代列表时删除对象,而不会抛出ConcurrentModification异常。