Не могу понять этот комментарий о 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);
Хотя это не очень хороший код для начала, в комментарии говорится, что этот код недействителен (в отличие, скажем, от неоптимального). Они говорят, что исключение может вообще не следовать, поэтому вышеприведенный цикл может молча вызвать сбой.