какая разница между итераторами с fail fast и fail safe поведением с примерами
Русские Блоги
Коллекция Java Fail-Fast механизм VS Fail-Safe механизм
Fail-Fast механизм
A fail-fast system is nothing but immediately report any failure that is likely to lead to failure. When a problem occurs, a fail-fast system fails immediately.
In Java, we can find this behavior with iterators. In case, you have called iterator on a collection object, and another thread tries to modify the collection object, then concurrent modification exception will be thrown. This is called fail-fast.
Классы коллекций, которые соответствуют механизму Fail-Fast, включают:
List:
Поточно-ориентированные коллекции, созданные с помощью Collections.synchronizedXXX (), также работают без сбоев
При обходе коллекции через Iterator структура коллекции изменяется, поэтому создается исключение ConcurrentModificationException:
Exception in thread «main» java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)
at java.util.HashMap$EntryIterator.next(HashMap.java:1471)
at java.util.HashMap$EntryIterator.next(HashMap.java:1469)
at MapTest.main(MapTest.java:17)
Принцип реализации отказоустойчивого механизма
Проходят modCount (Количество модификаций) домена, которого нужно достичь.
При построении Итератора передайте expectedModCount Запишите текущее количество модификаций:
При изменении карты с помощью метода put измените modCount Поле (Количество изменений) плюс 1: ++modCount; 。
При обходе Итератора по очереди судите expectedModCount Это с modCount равно:
Меры предосторожности
Безотказный механизм
In this case the iterator will make a copy of the internal data structure and iterates over the copied data structure. Thus any modifications done to the internal data structure will not effect the iterator.
Принцип: переход по копии исходной коллекции.
Есть две проблемы:
Отказоустойчивый итератор против отказоустойчивого итератора
Отказоустойчивый итератор против отказоустойчивого итератора
1. Вступление
В этой статье мы познакомим вас с концепцией Fail-Fast и Fail-SafeIterators.
Системы Fail-Fast прерывают работу настолько быстро, насколько это возможно, немедленно обнаруживая сбои и останавливая всю операцию.
Тогда какFail-Safe systems don’t abort an operation in the case of a failure. Such systems try to avoid raising failures as much as possible.
2. Fail-FastIterators
Отказоустойчивые итераторы в Java не действуют при изменении базовой коллекции.
Collections поддерживает внутренний счетчикmodCount. Каждый раз, когда элемент добавляется или удаляется изCollection, этот счетчик увеличивается.
При итерации при каждом вызовеnext() текущее значениеmodCount сравнивается с начальным значением. Если есть несоответствие, он выдаетConcurrentModificationException, что прерывает всю операцию.
Итераторы по умолчанию дляCollections изjava.util package, такие какArrayList,HashMap и т. Д. работают без сбоев.
В приведенном выше фрагменте кодаConcurrentModificationException создается в начале следующего цикла итерации после того, как модификация была выполнена.
Поведение Fail-Fast не гарантируется во всех сценариях, так как невозможно предсказать поведение в случае одновременных модификаций. These iterators throw ConcurrentModificationException on a best effort basis.
Если при итерацииCollection,an item is removed using Iterator‘s remove() method, that’s entirely safe and doesn’t throw an exception.
Однако, если для удаления элемента используется методCollection‘sremove(), он генерирует исключение:
3. Отказоустойчивые итераторы
Отказоустойчивые итераторы предпочитают отсутствие сбоев за неудобства обработки исключений.
Эти итераторы создают клон фактическогоCollection и перебирают его. Если после создания итератора происходит какое-либо изменение, копия все равно остается нетронутой. Следовательно, этиIterators продолжают цикл поCollection, даже если он был изменен.
Однако важно помнить, что действительно отказоустойчивого итератора не существует. Правильный термин слабо последовательный.
Это означает, чтоif aCollection is modified while being iterated over, what the Iterator sees is weakly guaranteed. Это поведение может отличаться для разныхCollections и задокументировано в документации Javadocs каждого такогоCollection.
Однако отказоустойчивыеIteratorsимеют несколько недостатков. Одним из недостатков является то, чтоIterator isn’t guaranteed to return updated data from the Collection, поскольку он работает с клоном, а не с фактическимCollection.
Iterators вCollections из пакетаjava.util.concurrent, напримерConcurrentHashMap,CopyOnWriteArrayList и т. д. являются отказоустойчивыми по своей природе.
В приведенном выше фрагменте кода мы используем Fail-SafeIterator. Следовательно, даже несмотря на то, что новый элемент добавляется кCollection во время итерации, он не вызывает исключения.
Итератор по умолчанию_ for the _ConcurrentHashMap слабо согласован. Это означает, что этотIterator может допускать параллельную модификацию, пересекает элементы в том виде, в каком они существовали, когда был построенIterator, и может (но не гарантированно) отражать изменения вCollection после построения Iterator.
Следовательно, в приведенном выше фрагменте кода итерация повторяется пять раз, что означаетit does detect the newly added element to the Collection.
4. Заключение
В этом руководстве мы увидели, что означают Fail-Safe и Fail-FastIterators и как они реализованы в Java.
Полный код, представленный в этой статье, доступенover on GitHub.
Паршин Павел
Главное меню
Вопросы и ответы на собеседовании по теме Java Collection Framework. Часть 3.
Другое
LinkedList позволяет добавлять элементы в начало и конец списка за константное время, что хорошо подходит для реализации интерфейса Deque (в отличие, например, от ArrayList ).
Класс java.util.Collections содержит исключительно статические методы для работы с коллекциями. В них входят методы, реализующие полиморфные алгоритмы (такие алгоритмы, использование которых возможно с разными видами структур данных), «оболочки», возвращающие новую коллекцию с инкапсулированной указанной структурой данных и некоторые другие методы.
7. Что такое « fail-fast поведение»?
Fail-fast поведение означает, что при возникновении ошибки или состояния, которое может привести к ошибке, система немедленно прекращает дальнейшую работу и уведомляет об этом.
Использование fail-fast подхода позволяет избежать недетерминированного поведения программы в течение времени. Также стоит отметить, что fail-fast поведение не может быть абсолютно гарантировано.
Помимо этого класс EnumSet предоставляет множество статических методов инициализации для упрощенного и удобного создания экземпляров.
Итерация по EnumSet осуществляется согласно порядку объявления элементов перечисления.
9. java.util.Stack — считается «устаревшим». Чем его рекомендуют заменять? Почему?
Рекомендуется использовать интерфейс Deque («дек», Double Ended Queue) и его реализации. Например:
Класс Stack появился в JDK 1.0 и расширяет класс Vector, наследуя его функционал, что несколько нарушает понятие стека (например, класс Vector предоставляет возможность обращаться к любому элементу по индексу). Также использование Deque позволяет следовать принципу программирования на уровне интерфейсов, а не конкретных реализаций, что облегчает дальнейшую поддержку разрабатываемого класса и повышает его гибкость, позволяя при необходимости менять реализацию дека на нужную.
10. Какая коллекция реализует дисциплину обслуживания FIFO?
11. Какая коллекция реализует дисциплину обслуживания FILO?
При добавлении элемента, который уже присутствует в LinkedHashMap (т.е. с одинаковым ключом), порядок итерации по элементам не изменяется.
Реализация LinkedHashSet отличается от HashSet поддержкой двухсвязанного списка, определяющего порядок итерации по элементам структуры данных. Элементы списка упорядочены согласно их порядку добавления в LinkedHashSet (insertion-order).
При добавлении элемента, который уже присутствует в LinkedHashSet (т.е. с одинаковым ключом), порядок итерации по элементам не изменяется.
16. Говорят, на LinkedHashMap легко сделать простенький кэш c «invalidation policy», знаете как?
Необходимо использовать LRU-алгоритм (Least Recently Used algorithm) и LinkedHashMap с access-order. В этом случае при обращении к элементу он будет перемещаться в конец списка, а наименее используемые элементы будут постепенно группироваться в начале списка.
Простой пример реализации кэша с очисткой старых значений при превышении указанного порога:
Стоит заметить, что LinkedHashMap не позволяет полностью реализовать LRU-алгоритм, поскольку при вставке уже имеющегося в коллекции элемента порядок итерации не меняется.
Fail Fast! принцип: Отлаживайте меньше и создавайте более надежное ПО
Предположим мы должны написать простую веб-страницу, которая отображает рядом с фонтаном предупреждение о том, что вода в нём загрязнена.
Следующий HTML-код выполняет эту задачу:
Результат работы этого кода в браузере будет выглядеть следующим образом:
На второй вопрос легко ответить. Достаточно выполнить ошибочный HTML-код в браузере. На момент написания статьи браузеры Firefox, Google Chrome, Internet Explorer, Opera и Safari покажут следующий результат:
Очевидно, что в браузерах используется подход Forgive!, так как наш сайт продолжил работу и не было никаких сообщений об ошибке. Единственное отличие в том, что теперь стало больше текста, выделенного жирным шрифтом. Но всё сообщение всё ещё отображается целиком и люди предупреждены. Незачем сильно беспокоиться!
Делаем вывод: подход Forgive! работает хорошо!
Давайте попробуем воспроизвести другую ошибку.Вместо тэга мы напишем незаконченный тэг перед словами DO NOT, следующим образом:
Ранее перечисленные браузеры покажут следующий результат:
Есть повод паниковать! Теперь наша программа делает абсолютно обратное тому, что мы хотим, чтобы она делала. Последствия ужасны. Наше приложение, призванное спасать жизни, мутирует в приложение-убийцу.
Делаем вывод: подход Forgive! работает плохо!
Как видно из приведённых примеров, последствия ошибки при использования Forgive! подхода очень отличаются и могут варьироваться от полностью безобидных до катастрофических. Итак, каким будет корректный ответ на вопрос «Что должно произойти?»
Однако, ситуация кардинально меняется, когда приложение выполняется у клиента после релиза. К сожалению, не существует правила-на-все-времена. Практика показывает, что обычно лучше и после релиза использовать подход Fail fast! по умолчанию. Конечный негативный результат выполнения приложения, которое игнорирует ошибки и просто продолжает выполняться непредсказуемо, обычно хуже, чем негативный результат от приложения, которое внезапно прекратило работу. Если приложение бухгалтерского учёта внезапно «упало», пользователь будет зол. Если приложение продолжило работу после возникновения ошибки и создало неверный результат, пользователь будет очень зол. «Зол» лучше чем «очень зол». В этой ситуации подход Fail fast! лучше.
Если функция возвращает код ошибки в случае возникновения трудностей, ты должен проверить код этой ошибки, даже если эта проверка троекратно увеличит размер кода твоего и вызовет боль в твоих пальцах, потому что если ты помыслишь «это не может случиться со мной», боги обязательно накажут тебя за высокомерие.
Контрактное программирование ещё один пример использования особенностей Fail fast!. Потому что неверные входные/выходные аргументы и атрибуты объектов немедленно определяются и вызывают ошибки в процессе выполнения.
Если Вы выбрали среду программирования (= язык программирования + библиотеки + фреймворки), которая придерживается этого важного правила, то Вы будете отлаживать меньше и создавать более надёжный код за меньшее время.
What are fail-safe & fail-fast Iterators in Java
There are two types of iterators in Java: fail-safe and fail-fast.
What does this mean, and is the difference between them?
4 Answers 4
«Fail-safe» (in engineering) means that something fails in a way that causes no or minimal damage. Strictly speaking, there is no such thing in Java as a fail-safe iterator. If an iterator fails (in the normal sense of «fail»), you can expect damage to occur.
I suspect that you actually mean «weakly consistent» iterators. The javadoc says:
«Most concurrent Collection implementations (including most Queues) also differ from the usual java.util conventions in that their Iterators and Spliterators provide weakly consistent rather than fast-fail traversal.»
Typically, weak consistency means that if a collection is modified concurrently with an iteration, the guarantees of what the iteration sees are weaker. (The details will be specified in each concurrent collection classes javadocs.)
The alternative to «fail-fast» and «weakly consistent» is semantic where the iteration fails unpredictably; e.g. to sometimes give the wrong answer or throw an unexpected exception. (This was the behavior of some standard implementations of the Enumeration API in early versions of Java.)
. and are they different from the iterator we use for collection.
Fail-fast iterators are typically implemented using a volatile counter on the collection object.
By contrast, weakly consistent iterators are typically light-weight and leverage properties of each concurrent collection’s internal data structures. There is no general pattern. If you are interested, read the source code for different collection classes.
«The fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.»