我在以下情况下收到ConcurrentModificationException错误。发生这种情况的行标有“<-------- ConcurrentModificationException”
List<ThemeCacheIndex> list = Collections.synchronizedList(themeCacheList);
synchronized (list) {
Iterator<ThemeCacheIndex> it = list.iterator();
while (it.hasNext()) {
ThemeCacheIndex themeCacheIndex = it.next(); <-------- ConcurrentModificationException
doSomething();
}
}
@Override
protected String doInBackground(String... params) {
someElementsToRemove = calculateWhichElementsToRemove();
for(int i=0 ; i < someElementsToRemove.size() ; i++){
themeCacheList.remove(someElementsToRemove.get(i));
}
}
我可以想象,这是一个并发的情况,但我想通过主线程上的同步列表来防止这种情况。
我似乎并不理解多线程和共享对象的概念。
有人可以帮我解决这个问题吗?我该如何防止这种冲突?
引用Collections
Javadoc:
返回由指定列表支持的同步(线程安全)列表。为了保证串行访问,必须通过返回的列表完成对后备列表的所有访问。
如果你的AsyncTask
修改了themeCacheList
,那么你所做的同步将无济于事,因为后备列表会被修改。
AsyncTask代码很好。为“主”线程代码执行此操作:
synchronized (themeCacheList) {
Iterator<ThemeCacheIndex> it = themeCacheList.iterator();
while (it.hasNext()) {
ThemeCacheIndex themeCacheIndex = it.next();
doSomething();
}
}
正如你所看到的,我已经删除了Collections.synchronizedList
,因为它是多余的,我正在themeCacheList
直接同步。
不确定我有一个很好的解决方案,但我想这两个例子显示了问题和可能的解决方案。 “可能重复的”答案没有显示任何解决方案,只是解释了什么是问题。
@Test
public void testFails(){
List<String> arr = new ArrayList<String>();
arr.add("I");
arr.add("hate");
arr.add("the");
arr.add("ConcurrentModificationException !");
Iterator i = arr.iterator();
arr.remove(2);
while(i.hasNext()){
System.out.println(i.next());
}
}
@Test
public void testWorks(){
List<String> arr = new CopyOnWriteArrayList<>();
arr.add("I");
arr.add("hate");
arr.add("the");
arr.add("ConcurrentModificationException !");
Iterator i = arr.iterator();
arr.remove(2);
while(i.hasNext()){
System.out.println(i.next());
}
}