¿Qué son los iteradores a prueba de fallas y rápidos en Java?

Respuestas:

84

Cuál es la diferencia entre ellos ...

"A prueba de fallas" ( en ingeniería ) significa que algo falla de una manera que no causa daños mínimos o nulos. Estrictamente hablando, no existe en Java un iterador a prueba de fallas. Si un iterador falla (en el sentido normal de "falla"), puede esperar que ocurran daños.

Sospecho que en realidad te refieres a iteradores "débilmente consistentes". El javadoc dice:

"La mayoría de las implementaciones de colecciones simultáneas (incluidas la mayoría de las colas) también se diferencian de las convenciones java.util habituales en que sus iteradores y divisores proporcionan un recorrido débilmente consistente en lugar de un error rápido".

Normalmente, una consistencia débil significa que si una colección se modifica al mismo tiempo que una iteración, las garantías de lo que ve la iteración son más débiles. (Los detalles se especificarán en cada javadocs de clases de colección concurrentes).

"Fail-fast" ( en el diseño de sistemas ) significa que la condición de falla se verifica agresivamente para que la condición de falla se detecte (cuando sea posible 1 ) antes de que se pueda hacer demasiado daño. En Java, un iterador a prueba de fallas falla al lanzar un ConcurrentModificationException.

La alternativa a "fallar rápido" y "débilmente consistente" es semántica donde la iteración falla de manera impredecible; por ejemplo, a veces dar una respuesta incorrecta o lanzar una excepción inesperada. (Este fue el comportamiento de algunas implementaciones estándar de la EnumerationAPI en las primeras versiones de Java).

... y son diferentes del iterador que usamos para la colección.

No. Estas son propiedades de los iteradores implementadas por tipos de colección estándar; es decir, "fallan rápido" o "débilmente consistentes" ... cuando se usan correctamente con respecto a la sincronización y el modelo de memoria Java 1 .


Los iteradores a prueba de fallas se implementan típicamente usando un volatilecontador en el objeto de colección.

  • Cuando se actualiza la colección, se incrementa el contador.
  • Cuando Iteratorse crea un, el valor actual del contador se incrusta en el Iteratorobjeto.
  • Cuando Iteratorse realiza una operación, el método compara los dos valores del contador y arroja un CME si son diferentes.

Por el contrario, los iteradores débilmente consistentes suelen ser livianos y aprovechan las propiedades de las estructuras de datos internas de cada colección concurrente. No existe un patrón general. Si está interesado, lea el código fuente de las diferentes clases de colección.


1 - El rider es que el comportamiento a prueba de fallas asume que la aplicación se identifica correctamente con respecto a la sincronización y el modelo de memoria. Eso significa que (por ejemplo) si itera ArrayListsin una sincronización adecuada, el resultado podría ser un resultado de lista dañado. El mecanismo de "falla rápida" probablemente detectará la modificación concurrente (aunque eso no está garantizado), pero no detectará la corrupción subyacente. Como ejemplo, javadoc for Vector.iterator()dice esto:

"El comportamiento a prueba de fallas de un iterador no se puede garantizar ya que, en términos generales, es imposible hacer garantías estrictas en presencia de una modificación concurrente no sincronizada. Los iteradores de falla rápida se lanzan ConcurrentModificationExceptionsobre la base del mejor esfuerzo. Por lo tanto, sería Es incorrecto escribir un programa que dependía de esta excepción para su corrección: el comportamiento rápido de fallas de los iteradores debe usarse solo para detectar errores ".

Stephen C
fuente
Quizás un poco irrelevante, pero también podría complementar esta pregunta. ¿Qué pasa con el estilo de instantánea que utiliza, por ejemplo, el CoW? Más específicamente, no entiendo cómo la matriz subyacente (o la instantánea) sobre la que itera el iterador de CoW "nunca" ve los cambios realizados por otros subprocesos, ya que todavía podemos solicitar setArraycualquier modificación.
stdout
Decidí que hablar sobre la implementación de iteradores débilmente consistentes está más allá del alcance de estas preguntas y respuestas.
Stephen C
42

Son tipos bastante rápidos y débilmente consistentes :

Iteradores del java.utillanzamiento del paquete ConcurrentModificationExceptionsi la colección fue modificada por los métodos de la colección (agregar / quitar) mientras se itera

Los iteradores del java.util.concurrentpaquete generalmente iteran sobre una instantánea y permiten modificaciones simultáneas, pero es posible que no reflejen las actualizaciones de la colección después de que se creó el iterador.

Evgeniy Dorofeev
fuente
El iterador es un ejemplo de falla rápida mientras que la enumeración es a prueba de fallas
Ajay Sharma
5
@AjaySharma - Incorrecto por dos razones. 1) Ni Iteratoro Enumerationespecificar el comportamiento como prueba de rápida o prueba de fallos. Son las implementaciones específicas (es decir, los métodos específicos de colección iterator()/ elements()etc. que devuelven estos objetos) las que especifican el comportamiento. 2) Las implementaciones típicas de enumeración no son rápidas ni a prueba de fallas .
Stephen C
22

La única diferencia es que el iterador a prueba de fallas no arroja ninguna excepción, al contrario que el iterador a prueba de fallas.

Si Collection se modifica estructuralmente mientras un subproceso está iterando sobre él. Esto se debe a que funcionan en el clon de Collection en lugar de en la colección original y por eso se denominan iteradores a prueba de fallos.

El iterador de CopyOnWriteArrayList es un ejemplo de iterador a prueba de fallas, también el iterador escrito por ConcurrentHashMap keySet también es un iterador a prueba de fallas y nunca lanza ConcurrentModificationException en Java.

Juned Ahsan
fuente
No veo que el iterador ConcurrentHashMap esté funcionando en clone () .. :( Algunas veces reflejará algunas de las actualizaciones mientras se itera ..
Kanagavelu Sugumar
0

Este escenario se relaciona con el "procesamiento concurrente", significa que más de un usuario accede al mismo recurso. En tal situación, uno de los usuarios intenta modificar ese recurso que causa la 'ConcurrentProcessingException' porque en ese caso otro usuario obtiene datos incorrectos. Tanto este tipo se relacionan con este tipo de situación.

En términos simples,

Fallar rapido :

  • Los iteradores lanzan inmediatamente ConcurrentModificationException si ocurre una modificación estructural (agregar, actualizar, eliminar).
  • Ejemplo: ArrayList, HashMap, TreeSet

A prueba de fallos :

  • Aquí los iteradores no arrojan ninguna excepción porque operan en el clon de la colección, no en el original. Entonces, son iteradores a prueba de fallas.
  • Ejemplo: CopyOnWriteArrayList, ConcurrentHashMap
Dhwanil Patel
fuente