ConcurrentModificationException с синхронизированным списком - PullRequest
0 голосов
/ 10 апреля 2019

Я получаю ошибку ConcurrentModificationException в следующей ситуации. Линия место, где это происходит, помечено как "<-------- ConcurrentModificationException" </p>

  • У меня есть основной поток, который читает из списка следующим образом:

    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 ]

1 голос
/ 10 апреля 2019

Цитирование Collections Javadoc :

Возвращает синхронизированный (потокобезопасный) список, поддерживаемый указанным списком.Чтобы гарантировать последовательный доступ, очень важно, чтобы весь доступ к списку поддержки осуществлялся через возвращенный список.

Если ваш AsyncTask изменяет themeCacheList, синхронизацию, как вы это делалине поможет, так как список поддержки изменен.

0 голосов
/ 10 апреля 2019

Не уверен, что у меня есть хорошее решение, но я думаю, что эти 2 примера показывают проблему и возможное решение. Ответы «Возможный дубликат» не показывают никакого решения, а просто объясняют, в чем проблема.

@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());
    }
}
0 голосов
/ 10 апреля 2019

Код AsyncTask в порядке. Сделайте это для "основного" кода потока:

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

Как видите, я удалил Collections.synchronizedList, потому что он избыточен, и я синхронизируюсь напрямую на themeCacheList.

...