Что такое отказоустойчивые и отказоустойчивые итераторы в Java
В Java есть два типа итераторов: отказоустойчивые и отказоустойчивые.
Что это значит, и есть ли разница между ними?
3 ответа
В чем разница между ними...
"Отказоустойчивость" означает: он не подведет. Строго говоря, в Java нет такой вещи, как отказоустойчивый итератор. Правильный термин "слабо последовательный". Javadoc говорит:
"Большинство одновременных реализаций Collection (включая большинство очередей) также отличаются от обычных соглашений java.util тем, что их итераторы и сплитераторы обеспечивают слабосогласованный, а не быстрый обход".
Как правило, слабая согласованность означает, что если коллекция изменяется одновременно с итерацией, гарантии того, что видит итерация, являются более слабыми. (Подробности будут указаны в каждом javadoc s классов параллельной коллекции.)
"Fail fast" означает: он может потерпеть неудачу... и условие отказа проверяется агрессивно, так что условие отказа (где это возможно 1) обнаруживается до того, как может быть нанесен ущерб. В Java отказоустойчивый итератор дает сбой, бросая ConcurrentModificationException
,
Альтернатива "отказоустойчивый" и "слабосогласованный" - это семантика, в которой итерация заканчивается непредсказуемо; например, иногда давать неправильный ответ или выдавать совершенно неожиданное исключение. (Это было поведение некоторых стандартных реализаций Enumeration
API в ранних версиях Java.)
... и они отличаются от итератора, который мы используем для сбора.
Нет. Это свойства итераторов, реализованных стандартными типами Collection; то есть они либо "быстро проваливаются", либо "слабо согласованы"... при правильном использовании в отношении синхронизации и модели памяти Java 1.
Отказоустойчивые итераторы обычно реализуются с использованием volatile
счетчик на объекте коллекции.
- Когда коллекция обновляется, счетчик увеличивается.
- Когда
Iterator
текущее значение счетчика встроено вIterator
объект. - Когда
Iterator
выполняется операция, метод сравнивает два значения счетчика и выдает CME, если они различаются.
Реализация отказоустойчивых итераторов обычно легковесна. Они обычно полагаются на свойства структур данных конкретной реализации списка. Там нет общей картины. (Прочитайте исходный код для конкретных классов коллекции, которые вас интересуют.)
1 - Райдер считает, что безотказное поведение предполагает, что приложение правильно идентифицируется в отношении синхронизации и модели памяти. Это означает, что (например), если вы повторяете ArrayList
без надлежащей синхронизации конечный результат мог бы быть результатом поврежденного списка. Механизм "быстрого отказа", вероятно, обнаружит одновременную модификацию (хотя это не гарантируется), но не обнаружит основную коррупцию. В качестве примера, Javadoc для Vector.iterator()
говорит это:
"Отказоустойчивое поведение итератора не может быть гарантировано, так как, вообще говоря, невозможно сделать какие-либо жесткие гарантии при наличии несинхронизированной параллельной модификации. Отказоустойчивые итераторы бросают
ConcurrentModificationException
на основе максимальных усилий. Следовательно, было бы неправильно писать программу, которая зависела от этого исключения в отношении его корректности: поведение итераторов, обеспечивающее отказоустойчивость, должно использоваться только для обнаружения ошибок ".
Это скорее отказоустойчивые и слабосогласованные типы:
Итераторы из java.util
пакет бросить ConcurrentModificationException
если коллекция была изменена методами коллекции (добавить / удалить) во время итерации
Итераторы из java.util.concurrent
Пакет обычно перебирает моментальный снимок и допускает одновременные изменения, но может не отражать обновления коллекции после создания итератора.
Единственная разница в том, что отказоустойчивый итератор не выдает никаких исключений, в отличие от отказоустойчивого итератора.
Если Коллекция изменена структурно, в то время как один поток перебирает ее. Это потому, что они работают с клоном Collection вместо оригинальной коллекции, и поэтому они называются отказоустойчивыми итераторами.
Итератор CopyOnWriteArrayList является примером отказоустойчивого итератора, также итератор, написанный ConcurrentHashMap, keySet также является отказоустойчивым итератором и никогда не генерирует исключение ConcurrentModificationException в Java.
Этот сценарий относится к "параллельной обработке", то есть к одному и тому же ресурсу обращаются более одного пользователя. В такой ситуации один из пользователей пытается изменить этот ресурс, что вызывает исключение ConcurrentProcessingException, потому что в этом случае другой пользователь получает неправильные данные. Оба типа относятся к подобным ситуациям.
Проще говоря,
Быстрый отказ:
- Итераторы немедленно генерируют исключение ConcurrentModificationException, если происходит структурная модификация (добавление, обновление, удаление).
- Пример: ArrayList, HashMap, TreeSet
Отказоустойчивый:
- Здесь итераторы не генерируют никаких исключений, потому что они работают с клоном коллекции, а не с исходной. Таким образом, они являются отказоустойчивыми итераторами.
- Пример: CopyOnWriteArrayList, ConcurrentHashMap