Що таке безпечні та невідповідні ітератори на Java


101

На Java існує два типи ітераторів: безпечний та безвідмовний.

Що це означає, і чи є різниця між ними?


3
найкраще посилання я знайшов javahungry.blogspot.com/2014/04/…
Premraj

2
Зауважте, що в специфікаціях Java SE не використовується термін "безпечний збій" для опису будь-яких ітераторів. Тому я рекомендую уникати цього терміну. Дивіться також stackoverflow.com/a/38341921/1441122
Stuart Marks

Відповіді:


84

Яка різниця між ними ...

"Наявність відмов" ( в техніці ) означає, що щось виходить з ладу таким чином, що не завдає ніякої або мінімальної шкоди. Власне кажучи, у Java немає такого поняття, як ідентифікатор відмови. Якщо ітератор виходить з ладу (у звичайному розумінні "виходить з ладу"), ви можете очікувати, що це може призвести до пошкодження.

Я підозрюю, що ви насправді маєте на увазі "слабо послідовних" ітераторів. Явадок каже:

"Більшість одночасних реалізацій колекції (включаючи більшість черг) також відрізняються від звичайних конвенцій java.util тим, що їх Ітератори та Спілітератори забезпечують слабко послідовний, а не швидкий вихід з ладу."

Зазвичай слабка консистенція означає, що якщо колекція модифікується одночасно з ітерацією, гарантії того, що бачить ітерація, слабкіші. (Деталі будуть вказані у кожному паралельному класі колекціонування javadocs.)

"Невдалий збій" ( в дизайні систем ) означає, що стан відмови перевіряється агресивно, щоб було виявлено стан відмови (де це можливо 1 ) перед тим, як завдати занадто великої шкоди. У Java невдалий ітератор виходить з ладу, кинувши a ConcurrentModificationException.

Альтернатива "невдалому" та "слабо послідовному" є семантичним, коли ітерація не вдається непередбачувано; наприклад, іноді дати неправильну відповідь або кинути несподіваний виняток. (Це було поведінкою деяких стандартних реалізацій EnumerationAPI в ранніх версіях Java.)

... і чим вони відрізняються від ітератора, який ми використовуємо для колекції.

Ні. Це властивості ітераторів, реалізованих стандартними типами колекції; тобто вони або "швидко виходять з ладу", або "слабо узгоджуються" ... при правильному використанні стосовно синхронізації та моделі пам'яті Java 1 .


Збійні ітератори зазвичай реалізуються за допомогою volatileлічильника на об'єкті колекції.

  • Коли колекція оновлюється, лічильник збільшується.
  • Коли Iteratorстворюється, поточне значення лічильника вбудовується в Iteratorоб'єкт.
  • Коли Iteratorвиконується операція, метод порівнює два значення лічильника і кидає CME, якщо вони різні.

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


1 - Наїзник полягає в тому, що невдала поведінка передбачає, що програма ідентифікує правильно стосовно синхронізації та моделі пам'яті. Це означає, що (наприклад), якщо ви повторюєте ArrayListбез належної синхронізації, результат може бути пошкодженим результатом списку. Механізм "швидкого виходу з ладу", ймовірно, виявить одночасну модифікацію (хоча це не гарантується), але він не виявить основної корупції. Як приклад, javadoc for Vector.iterator()говорить про це:

"Неможливо гарантувати поведінку ітератора, оскільки це, загалом кажучи, неможливо дати будь-які жорсткі гарантії за наявності несинхронізованих одночасних модифікацій. Невдалі ітератори відкидаються ConcurrentModificationExceptionна основі найкращих зусиль. Тому було б неправильно писати програму, яка залежала від цього винятку за її правильність: невдала поведінка ітераторів повинна використовуватися лише для виявлення помилок ".


Можливо, трохи не має значення, але також може доповнювати це питання. Як щодо стилю знімків, яким користується, наприклад, Корова? Більш конкретно, я не зовсім розумію, що базовий масив (або знімок), який ітератор CoW повторює "ніколи", не бачить змін, які вносяться іншими потоками, оскільки ми все ще можемо викликати setArrayбудь-які зміни.
stdout

Я вирішив, що говорити про реалізацію слабо послідовних ітераторів виходить за межі цього питання запитань.
Стівен С

42

Вони досить швидкі та слабкозмінні типи:

Ітератори від java.utilкидання пакетуConcurrentModificationException якщо колекція була змінена методами колекції (додавання / видалення) під час ітерації

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


Ітератор є прикладом виходу з ладу, тоді як перерахування не захищене
Ajay Sharma

5
@AjaySharma - Невірно за двома пунктами. 1) Ні Iteratorта не Enumerationвказуйте поведінку як невдалий або невдалий. Саме поведінка визначає конкретні реалізації (тобто конкретні методи колекції iterator()/ elements()тощо), які визначають поведінку. 2) Типові реалізації перерахування не є ані швидкими, ані безпечними .
Stephen C

22

Єдина відмінність полягає в тому, що безпечний ітератор не викидає жодного винятку, на відміну від швидкодіючого ітератора.

Якщо колекція структурно модифікована, тоді як одна нитка перекручується над нею. Це відбувається тому, що вони працюють над клоном колекції замість оригінальної колекції, і тому їх називають невідправним ітератором.

Iterator CopyOnWriteArrayList є прикладом невдалого Iterator також ітератора, написаного ConcurrentHashMap keySet також є безпечним ітератором і ніколи не кидає ConcurrentModificationException в Java.


Я не бачу, ітератор ConcurrentHashMap працює над клоном () .. :(
Деколи

0

Цей сценарій пов'язаний з "одночасною обробкою", означає, що більше одного користувача отримують доступ до одного і того ж ресурсу. У такій ситуації один з користувачів намагається змінити той ресурс, який викликає "ConcurrentProcessingException", оскільки в такому випадку інший користувач отримує неправильні дані. Обидва цього типу пов'язані з такою ситуацією.

Простіше кажучи,

Невдалий:

  • Ітератори негайно кидають ConcurrentModificationException, якщо відбудеться структурна модифікація (додавання, оновлення, видалення).
  • Приклад: ArrayList, HashMap, TreeSet

Безаварійності :

  • Тут Ітератори не кидають жодного винятку, оскільки вони працюють на клоні колекції, а не на оригінальній. Отже, що вони є безпечними ітераторами.
  • Приклад: CopyOnWriteArrayList, ConcurrentHashMap
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.