Что такое отказоустойчивые и отказоустойчивые итераторы в Java

101

В Java есть два типа итераторов: отказоустойчивые и отказоустойчивые.

Что это значит, и чем они отличаются?

Prateek
источник
3
лучшая ссылка, которую я нашел javahungry.blogspot.com/2014/04/…
Premraj
2
Обратите внимание, что в спецификациях Java SE не используется термин «отказоустойчивый» для описания каких-либо итераторов. Поэтому я рекомендую избегать этого термина. См. Также stackoverflow.com/a/38341921/1441122
Стюарт Маркс

Ответы:

84

В чем разница между ними ...

«Отказоустойчивый» ( в инженерии ) означает, что что-то выходит из строя так, что не причиняет никакого ущерба или причиняет им минимальный ущерб. Строго говоря, в Java нет такого понятия, как отказоустойчивый итератор. Если итератор выходит из строя (в обычном смысле слова «сбой»), вы можете ожидать повреждения.

Я подозреваю, что вы на самом деле имеете в виду «слабо согласованные» итераторы. В javadoc говорится:

«Большинство реализаций параллельных коллекций (включая большинство очередей) также отличаются от обычных соглашений java.util тем, что их итераторы и сплитераторы обеспечивают слабо согласованный, а не быстрый обход».

Как правило, слабая согласованность означает, что если коллекция изменяется одновременно с итерацией, гарантии того, что видит итерация, слабее. (Подробности будут указаны в документации javadocs для каждого параллельного набора классов.)

«Безотказный» ( в проектировании систем ) означает, что условие отказа тщательно проверяется, так что условие отказа (где возможно 1 ) обнаруживается до того, как может быть нанесен слишком большой ущерб. В Java отказоустойчивый итератор дает сбой, создавая ConcurrentModificationException.

Альтернатива «отказоустойчивому» и «слабо согласованному» является семантическим, когда итерация терпит неудачу непредсказуемо; например, иногда давать неправильный ответ или генерировать неожиданное исключение. (Это было поведение некоторых стандартных реализаций EnumerationAPI в ранних версиях Java.)

... и отличаются ли они от итератора, который мы используем для сбора.

Нет. Это свойства итераторов, реализованные стандартными типами Collection; т.е. они либо «быстро выходят из строя», либо «слабо согласованы» ... при правильном использовании в отношении синхронизации и модели памяти Java 1 .


Отказоустойчивые итераторы обычно реализуются с использованием volatileсчетчика в объекте коллекции.

  • Когда коллекция обновляется, счетчик увеличивается.
  • Когда Iteratorсоздается, текущее значение счетчика внедряется в Iteratorобъект.
  • Когда Iteratorоперация выполняется, метод сравнивает два значения счетчика и выдает CME, если они различны.

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


1 - Наездник заключается в том, что безотказное поведение предполагает, что идентификатор приложения правильный в отношении синхронизации и модели памяти. Это означает, что (например), если вы выполняете итерацию ArrayListбез надлежащей синхронизации, результатом может быть поврежденный результат списка. Механизм «быстрого сбоя», вероятно, обнаружит одновременную модификацию (хотя это не гарантируется), но не обнаружит лежащее в основе повреждение. Например, в javadoc for Vector.iterator()сказано следующее:

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

Стивен С
источник
Может быть, немного неактуально, но также может дополнять этот вопрос. А как насчет стиля снимков, который используется, например, в CoW? Точнее, я не совсем понимаю, как базовый массив (или снимок), который итератор CoW выполняет итерацию, «никогда» не видит никаких изменений, внесенных другими потоками, поскольку мы все еще можем вызывать setArrayлюбые изменения.
stdout
Я решил, что разговор о реализации слабосогласованных итераторов выходит за рамки этого вопроса.
Стивен С.
42

Это довольно отказоустойчивые и слабосогласованные типы:

Итераторы из java.utilпакета бросают, ConcurrentModificationExceptionесли коллекция была изменена методами коллекции (добавление / удаление) во время итерации

Итераторы из java.util.concurrentпакета обычно выполняют итерацию по снимку и допускают одновременные изменения, но могут не отражать обновления коллекции после создания итератора.

Евгений Дорофеев
источник
Итератор - это пример отказоустойчивости при отказоустойчивом перечислении
Аджай Шарма
5
@AjaySharma - Неверно по двум причинам. 1) Ни Iteratorили не Enumerationуказывайте поведение как отказоустойчивое или отказоустойчивое. Это конкретные реализации (т.е. определенные методы коллекции iterator()/ и elements()т.д., которые возвращают эти объекты), которые определяют поведение. 2) Типичные реализации перечисления не являются ни отказоустойчивыми, ни отказоустойчивыми .
Stephen C
22

Единственная разница в том, что отказоустойчивый итератор не генерирует никаких исключений, в отличие от отказоустойчивого итератора.

Если Collection модифицируется структурно, пока один поток выполняет итерацию по нему. Это связано с тем, что они работают с клоном Collection вместо исходной коллекции, и поэтому они называются отказоустойчивым итератором.

Итератор CopyOnWriteArrayList является примером отказоустойчивого итератора. Итератор, написанный ConcurrentHashMap keySet, также является отказоустойчивым итератором и никогда не генерирует исключение ConcurrentModificationException в Java.

Джунед Ахсан
источник
Я не вижу, что итератор ConcurrentHashMap работает над clone () .. :( Иногда он будет отражать некоторые обновления во время итерации ..
Канагавелу Сугумар,
0

Этот сценарий связан с «параллельной обработкой», что означает, что к одному и тому же ресурсу обращаются более одного пользователя. В такой ситуации один из пользователей пытается изменить этот ресурс, что вызывает исключение ConcurrentProcessingException, потому что в этом случае другой пользователь получает неправильные данные. Оба эти типа относятся к подобным ситуациям.

Проще говоря,

Быстрый отказ:

  • Итераторы немедленно генерируют исключение ConcurrentModificationException, если происходит структурная модификация (добавление, обновление, удаление).
  • Пример: ArrayList, HashMap, TreeSet

Отказоустойчивый:

  • Здесь итераторы не генерируют никаких исключений, потому что они работают с клоном коллекции, а не с исходной. Таким образом, они являются отказоустойчивыми итераторами.
  • Пример: CopyOnWriteArrayList, ConcurrentHashMap
Дхванил Патель
источник