简体   繁体   English

List.addAll生成的遍历List是否在Java中产生ConcurrentModificationException?

[英]Does traverse List generated by List.addAll produce ConcurrentModificationException in Java?

Code post below produced ConcurrentModificationException , newMR is ensured not modified in the loop, mkrs is thread unsafely in concurrent environment. 后置代号低于生产ConcurrentModificationExceptionnewMR保证不会在环路修改, mkrs是线程不安全并发环境。 It is known that List.addAll is implemented by System.arraycopy which is intrinsic method in JVM. 众所周知List.addAll是由System.arraycopy实现的, System.arraycopy是JVM中的固有方法。 Does traverse List generated by List.addAll produce ConcurrentModificationException in Java? List.addAll生成的遍历List是否在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));
    }
}

Post the exception stack trace happened on an Android machine. 发布发生在Android机器上的异常堆栈跟踪。 Note that (ProGuard:433) is the line where for (Foo mkr : newMR) written. 注意(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)

The javadoc for ArrayList.addAll states: ArrayList.addAllJavadoc状态为:

"The behavior of this operation is undefined if the specified collection is modified while the operation is in progress." “如果在操作进行过程中修改了指定的集合,则此操作的行为是不确定的。”

So consider this: 所以考虑一下:

newMR.addAll(mkrs);

The addAll method is going to have to iterate the mkrs collection. addAll方法将必须迭代mkrs集合。

If mkrs is modified by another thread while you are calling addAll(mkrs) , then a CCME is possible if the type of mkrs is not a concurrent collection that allows simultaneous iteration and updates. 如果mkrs被另一个线程,而你正在修改调用addAll(mkrs)那么CCME是可能的,如果类型mkrs不是并发收集,允许同时进行迭代和更新。

newMR.addAll(mkrs); iterates over mkrs, mrm.getFooPush() . 遍历mkrs, mrm.getFooPush() If that list is changed during the addAll, you get that message. 如果在addAll期间更改了该列表,则会收到该消息。

You need to have a concurrency safe list (inside getFooPush) or a better data structure. 您需要有一个并发安全列表(在getFooPush内部)或更好的数据结构。 Like a queue if the messages are added at the end, and you are filtered (on PushRecommend) consuming from the front. 就像队列一样,如果消息是在末尾添加的,并且您被过滤掉(在PushRecommend上),则从头开始消耗。

Then there is no need to make a copy. 这样就无需进行复制。

As already mentioned, the original data structure could be made safe by Collections.synchronizedList(list) . 如前所述,可以通过Collections.synchronizedList(list)使原始数据结构安全。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM