确保在循环中不修改下面产生的ConcurrentModificationException
,newMR
下的代码,mkrs
在并发环境中是不安全的线程。众所周知List.addAll
是由System.arraycopy
实现的,它是JVM中的固有方法。由List
生成的List.addAll
遍历在Java中产生ConcurrentModificationException
吗?
ArrayList<Foo> mkrs = mrm.getFooPush();
ArrayList<Foo> newMR = new ArrayList<Foo>(mkrs.size());
newMR.addAll(mkrs);
for (Foo mkr : newMR) {
if (mkr != null && mkr instanceof PushRecommend) {
PushRecommend pr = (PushRecommend) mkr;
recommendList.add(new MayKnowMessage(pr));
}
}
发布在Android机器上发生的异常堆栈跟踪。请注意,(ProGuard:433)
是for (Foo mkr : newMR)
写入的行。
java.util.ConcurrentModificationException:
java.util.ArrayList$Itr.next(ArrayList.java:837)
NewFriendManager.void loadNewFriendMsg(boolean)(ProGuard:433)
NewFriendManager.void reloadNewFriendMsg()(ProGuard:308)
NewFriendManager.boolean handleMessage(android.os.Message)(ProGuard:144)
android.os.Handler.dispatchMessage(Handler.java:106)
android.os.Looper.loop(Looper.java:232)
android.os.HandlerThread.run(HandlerThread.java:61)
答案 0 :(得分:1)
ArrayList.addAll
的{{3}}状态:
“如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。”
所以考虑一下:
newMR.addAll(mkrs);
addAll
方法将必须迭代mkrs
集合。
如果在调用mkrs
时addAll(mkrs)
被另一个线程修改,则如果mkrs
的类型不是允许同时迭代和更新的并发集合,则CCME是可能的。
答案 1 :(得分:1)
newMR.addAll(mkrs);
遍历mkrs, mrm.getFooPush()
。
如果在addAll期间更改了该列表,则会收到该消息。
您需要有一个并发安全列表(在getFooPush内部)或更好的数据结构。就像队列一样,如果消息是在末尾添加的,并且您被过滤掉(在PushRecommend上),则从头开始消耗。
然后无需进行复制。
如前所述,Collections.synchronizedList(list)
可以使原始数据结构安全。