带有同步列表的ConcurrentModificationException

时间:2019-04-10 15:53:53

标签: java multithreading concurrentmodification

在以下情况下,我收到一个ConcurrentModificationException错误。线 发生这种情况的地方标记为“ <-------- ConcurrentModificationException”

  • 我有一个从列表中读取的主线程,如下所示:

    List<ThemeCacheIndex> list = Collections.synchronizedList(themeCacheList);
    synchronized (list) {
        Iterator<ThemeCacheIndex> it = list.iterator();
        while (it.hasNext()) {
            ThemeCacheIndex themeCacheIndex = it.next();  <-------- ConcurrentModificationException
            doSomething();
        }
    }
    
  • 我有一个AsyncTask将从此列表中删除:

     @Override
        protected String doInBackground(String... params) {
            someElementsToRemove = calculateWhichElementsToRemove();
            for(int i=0 ; i < someElementsToRemove.size() ; i++){
                themeCacheList.remove(someElementsToRemove.get(i));
            }
        }
    

我可以想象,这涉及到并发情况,但是我想通过在主线程上使用同步列表来阻止这种情况。

似乎我不了解多线程和共享对象的概念。

有人可以帮助我解决这个问题吗?如何防止这种冲突?

3 个答案:

答案 0 :(得分:1)

引用Collections Javadoc

  

返回由指定对象支持的同步(线程安全)列表   清单。为了保证串行访问,至关重要的是所有   通过返回的列表可以访问后备列表。

如果您的AsyncTask修改了themeCacheList,则同步操作将无济于事,因为后备列表被修改了。

答案 1 :(得分:0)

AsyncTask代码很好。对“主”线程代码执行此操作:

synchronized (themeCacheList) {
    Iterator<ThemeCacheIndex> it = themeCacheList.iterator();
    while (it.hasNext()) {
        ThemeCacheIndex themeCacheIndex = it.next();
        doSomething();
    }
}

如您所见,我已经删除了Collections.synchronizedList,因为它是多余的,我直接在themeCacheList上进行了同步。

答案 2 :(得分:0)

不确定我有一个好的解决方案,但是我想这两个示例可以说明问题和可能的解决方案。 “可能重复”答案没有显示任何解决方案,而只是在说明问题所在。

@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());
    }
}