Исключение ConcurrentModificationException при удалении элемента из списка - PullRequest
0 голосов
/ 26 июня 2018

Я должен удалить элемент из списка, который я перебираю из хранилища.Это вызовет исключение ConcurrentModificationException даже с использованием Iterator.Этот код будет выполнен в конце действия.См. Iter1.remove ().Пожалуйста, предложите, если есть какие-то обходные пути.

List<OfflineCommand> l_loc = (List<OfflineCommand>) Storage.getInstance().readObject("LocationTest"); 
            if (l_loc != null) {                
                boolean flgSuccess = true;
                ListIterator<OfflineCommand> iter1 = l_loc.listIterator();
                while (iter1.hasNext()) {
                    OfflineCommand oc = iter1.next();
                    flgSuccess = executeOfflineCommand(oc);
                    if (!flgSuccess) {
                        break;
                    } else {
                        iter1.remove();
                    }
                }
            }

В другом месте я использую следующий код для добавления записи в тот же список для каждой минуты.

 List<OfflineCommand> l_noAppt = Storage.getInstance().readObject("LocationTest");
            if (l_noAppt == null) {
                l_noAppt = new ArrayList<>();
            }
            l_noAppt.add(new OfflineCommand(name, args));
            Storage.getInstance().writeObject("LocationTest", l_noAppt);

Ответы [ 3 ]

0 голосов
/ 26 июня 2018

После вызова remove() экземпляр Iterator становится недействительным.Есть несколько обходных путей для этого.Поскольку вы удаляете все элементы вплоть до неудачной записи, что-то вроде этого будет работать iter1 = l_loc.listIterator(); или в контексте:

            while (iter1.hasNext()) {
                OfflineCommand oc = iter1.next();
                flgSuccess = executeOfflineCommand(oc);
                if (!flgSuccess) {
                    break;
                } else {
                    iter1.remove();
                    iter1 = l_loc.listIterator();
                }
            }
0 голосов
/ 26 июня 2018

Добавление элемента в одном месте и одновременное удаление в другом месте требует синхронизации.

A) Использование Вектор .

Вектор обеспечивает синхронизациюиз коробки.Но даже для Vector не использует Iterator , потому что у вас есть одновременные модификации.

// On the place where you create your list now, create a Vector,
// like ... = new Vector<...>() instead of ... = new ArrayList<...>().
// Just a cast is not sufficient of course.
Vector<OfflineCommand> l_loc = ...;
if (l_loc != null) {                
  boolean flgSuccess = true;
  while (!l_loc.isEmpty()) {
    OfflineCommand oc = l_loc.get(0);
    flgSuccess = executeOfflineCommand(oc);
    if (!flgSuccess) {
      break;
    } else {
      l_loc.remove(0);
    }
  }
}

Преимущество: вам не нужна явная синхронизация.Ваш код остается компактным.

B) Используйте явную синхронизацию.

List<OfflineCommand> l_loc = ...;
if (l_loc != null) {                
  boolean flgSuccess = true;
  while (!l_loc.isEmpty()) {
    OfflineCommand oc = l_loc.get(0);
    flgSuccess = executeOfflineCommand(oc);
    if (!flgSuccess) {
      break;
    } else {
      synchronized (l_loc) {
        l_loc.remove(0);
      }
    }
  }
}

Важно: В месте, где вы добавляете объекты в этот список, вы также должны использовать синхронизацию:

synchronized(l_loc) {
  l_loc.add(...);
}

Второй подход не так надежен, потому что вы должны помнить все места, где ваш список может быть изменен, и использовать синхронизацию там.

Оба эти подхода, A и B, решит проблему с одновременной модификацией.

0 голосов
/ 26 июня 2018

Ваш вопрос неопределенный.Чтобы избежать ConcurrentModificationException, используйте ConcurrentHashMap и используйте вместо этого цикл FOR.

...