Не могу понять этот комментарий о fail-fast

В HashSet.java в JDK 1.6 есть несколько комментариев о свойстве fail-fast итератора HashSet.

Итераторы, возвращаемые методом итератора этого класса, не подвержены сбоям: если набор изменяется в любое время после создания итератора, любым способом, кроме как через собственный метод удаления итератора, итератор генерирует исключение ConcurrentModificationException. Таким образом, перед одновременной модификацией итератор быстро и чисто дает сбой, вместо того, чтобы рисковать произвольным недетерминированным поведением в неопределенное время в будущем.

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

Обратите внимание, что отказоустойчивое поведение итератора не может быть гарантировано, так как, вообще говоря, невозможно сделать какие-либо жесткие гарантии при наличии несинхронизированной параллельной модификации. Отказоустойчивые итераторы создают исключительную ситуацию ConcurrentModificationException. Следовательно, было бы неправильно писать программу, которая зависела от этого исключения в отношении его корректности: поведение итераторов, обеспечивающее отказоустойчивость, следует использовать только для обнаружения ошибок.

2 ответа

Решение

РЕДАКТИРОВАТЬ: Извините, я использовал список, но это та же идея. Это касается итератора, а не коллекции за ним.

РЕДАКТИРОВАТЬ 2: Кроме того, это гораздо чаще случается в многопоточной среде, где у вас есть два потока, одно чтение, одно запись. Это труднее увидеть, когда вы кодируете. Чтобы исправить это, вам нужно внедрить блокировки чтения / записи в список, чтобы избежать этого.

Вот пример кода для комментария:

Iterator itr = myList.iterator();

while(itr.hasNext())
{
    Object o = itr.next();

    if(o meets some condition)
    { 
        //YOURE MODIFYING THE LIST
        myList.remove(o);
    }
}

Спецификации говорят о том, что вы не можете полагаться на такой код:

while(itr.hasNext())
{
     Object o = itr.next();

     try
     {
         if(o meets some condition)
            myList.remove(o);
     }
     catch(ConcurrentModificationException e)
     {
         //Whoops I abused my iterator. Do something else.
     }
}

Вместо этого вам, вероятно, следует добавить что-то в новый список, а затем переключить ссылку myList на только что созданный. Это объясняет ситуацию?

Идея, стоящая за вторым абзацем, состоит в том, чтобы помешать вам писать такой код:

boolean ok = false;
do {
    try {
        doTheModification();
        ok = true;
    } catch {
        // Consurrent modification - retry
    }
} while (!ok);

Хотя это не очень хороший код для начала, в комментарии говорится, что этот код недействителен (в отличие, скажем, от неоптимального). Они говорят, что исключение может вообще не следовать, поэтому вышеприведенный цикл может молча вызвать сбой.

Другие вопросы по тегам