我有时会从以下代码中获得以下异常 人们建议如果我将for循环设置为迭代器,它将解决问题。但我不明白如果我没有删除for循环中的任何元素但是调用pendingActions.clear();后来。 如果有人遇到任何这种情况,请告诉我。 另外,您是否会考虑我是否将列表声明发送到
private List<Action> pendingActions = Collections.synchronizedList(new ArrayList<>());
会解决问题吗?
private List<Action> pendingActions = new ArrayList<>();
private void runPendingNavigationActions() {
if (!pendingActions.isEmpty()) {
for (Action r : pendingActions) {
r.run();
}
pendingActions.clear();
}
}
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4156)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1839)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Caused by: java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
at com.app.android.view.fragment.MainFragment.runPendingNavigationActions(MainFragment.java:1355)
答案 0 :(得分:3)
您使用的是错误的数据结构:Queue
是更好的选择,特别是为并发修改而设计的。
例如,您可以使用LinkedBlockingQueue
。您可以像列表一样添加到此列表,然后使用添加的操作,如:
Action r;
while ((r = queue.poll()) != null) {
r.run();
}
使用Collections.synchronizedList
无法解决您的问题,至少不会解决问题。
关于使用Collections.synchronizedList()
打包列表需要注意的事项是,它只为每个单独的方法调用提供互斥,例如:直到调用pendingActions.get()
或pendingActions.iterator()
为止。
增强的for循环隐式创建Iterator
;但是当你迭代它时,列表不会被锁定,无论它是否来自同步列表。
您的其他线程正在更改此迭代期间的列表,并且下次尝试从迭代器获取值时仍会导致ConcurrentModificationException
。
现在,您可以通过将迭代包装在synchronized
块以及中来使其工作(没有CME):
synchronized (pendingActions) {
for (Action r : pendingActions) {
r.run();
}
r.clear();
}
这个问题是,在迭代列表时,现在将阻止其他线程。这可能会导致您的应用显着延迟;或者它可能不会,这取决于调用此方法的频率,以及操作运行的时间。
然而,使用并发队列完全避免了这个问题,并且可能比同步列表更快,因为非阻塞并发队列不需要使用&#34;全面发布&#34 ;同步。