O que são Iteradores fail-safe e fail-fast em Java

101

Existem dois tipos de iteradores em Java: fail-safe e fail-fast.

O que isso significa e qual é a diferença entre eles?

Prateek
fonte
3
melhor link que encontrei javahungry.blogspot.com/2014/04/…
Premraj
2
Observe que as especificações do Java SE não usam o termo "à prova de falhas" para descrever quaisquer iteradores. Portanto, recomendo evitar esse termo. Consulte também stackoverflow.com/a/38341921/1441122
Stuart Marks

Respostas:

84

Qual a diferença entre eles ...

"À prova de falhas" ( em engenharia ) significa que algo falha de uma forma que não causa nenhum ou mínimo dano. A rigor, não existe em Java um iterador à prova de falhas. Se um iterador falhar (no sentido normal de "falha"), você pode esperar que ocorram danos.

Eu suspeito que você realmente quer dizer iteradores "fracamente consistentes". O javadoc diz:

"A maioria das implementações de coleção simultâneas (incluindo a maioria das filas) também difere das convenções java.util usuais, pois seus Iteradores e Divisores fornecem consistência fraca em vez de travessia com falha rápida."

Normalmente, consistência fraca significa que se uma coleção for modificada simultaneamente com uma iteração, as garantias do que a iteração vê são mais fracas. (Os detalhes serão especificados em cada javadocs de classes de coleção simultâneas.)

"Fail-fast" ( no projeto de sistemas ) significa que a condição de falha é verificada agressivamente para que a condição de falha seja (quando possível 1 ) detectada antes que muito dano possa ser feito. Em Java, um iterador rápido falha lançando um ConcurrentModificationException.

A alternativa para "fail-fast" e "fracamente consistente" é semântica, onde a iteração falha imprevisivelmente; por exemplo, às vezes dar a resposta errada ou lançar uma exceção inesperada. (Esse era o comportamento de algumas implementações padrão da EnumerationAPI nas primeiras versões do Java.)

... e são diferentes do iterador que usamos para coleta.

Não. Essas são propriedades dos iteradores implementados por tipos de coleção padrão; ou seja, eles são "falha rápido" ou "consistentes fracamente" ... quando usados ​​corretamente com relação à sincronização e ao modelo de memória Java 1 .


Os iteradores fail-fast são geralmente implementados usando um volatilecontador no objeto de coleção.

  • Quando a coleção é atualizada, o contador é incrementado.
  • Quando um Iteratoré criado, o valor atual do contador é incorporado ao Iteratorobjeto.
  • Quando uma Iteratoroperação é executada, o método compara os dois valores do contador e lança um CME se eles forem diferentes.

Por outro lado, iteradores fracamente consistentes são normalmente propriedades leves e de aproveitamento das estruturas de dados internas de cada coleção simultânea. Não existe um padrão geral. Se você estiver interessado, leia o código-fonte para diferentes classes de coleção.


1 - O rider é que o comportamento fail-fast assume que o aplicativo id corretamente com relação à sincronização e ao modelo de memória. Isso significa que (por exemplo) se você iterar um ArrayListsem a sincronização adequada, o resultado pode ser um resultado de lista corrompido. O mecanismo de "falha rápida" provavelmente detectará a modificação simultânea (embora isso não seja garantido), mas não detectará a corrupção subjacente. Por exemplo, javadoc para Vector.iterator()diz o seguinte:

"O comportamento fail-fast de um iterador não pode ser garantido, pois é, de modo geral, impossível fazer quaisquer garantias rígidas na presença de modificação simultânea não sincronizada. Iteradores fail-fast jogam ConcurrentModificationExceptioncom base no melhor esforço. Portanto, seria errado escrever um programa que dependia desta exceção para sua correção: o comportamento rápido de falha dos iteradores deve ser usado apenas para detectar bugs. "

Stephen C
fonte
Talvez um pouco irrelevante, mas também pode complementar essa questão. E quanto ao estilo de instantâneo usado, por exemplo, pelo CoW? Mais especificamente, não consigo entender como o array subjacente (ou o instantâneo) que o iterador CoW itera sobre "nunca" vê as alterações feitas por outros threads, pois ainda somos capazes de chamar setArrayqualquer modificação.
stdout
Decidi que falar sobre a implementação de iteradores fracamente consistentes está além do escopo deste Q&A.
Stephen C
42

Eles são tipos bastante rápidos e fracamente consistentes :

Iteradores do java.utilpacote lançam ConcurrentModificationExceptionse a coleção foi modificada pelos métodos da coleção (adicionar / remover) durante a iteração

Os iteradores do java.util.concurrentpacote geralmente iteram sobre um instantâneo e permitem modificações simultâneas, mas podem não refletir as atualizações da coleção depois que o iterador foi criado.

Evgeniy Dorofeev
fonte
Iterator é um exemplo de fail-fast, enquanto a enumeração é fail-safe
Ajay Sharma,
5
@AjaySharma - Incorreto em dois pontos. 1) Nem Iteratorou Enumerationespecificar o comportamento como fail-rápido ou à prova de falhas. São implementações específicas (ou seja, os métodos específicos de coleção iterator()/ elements()etc que retornam esses objetos) que especificam o comportamento. 2) As implementações típicas de enumeração não são nem rápidas nem à prova de falhas .
Stephen C
22

A única diferença é que o iterador à prova de falhas não lança nenhuma exceção, ao contrário do Iterador rápido à falha.

If Collection é modificado estruturalmente enquanto um thread está iterando sobre ele. Isso ocorre porque eles trabalham no clone da coleção em vez da coleção original e é por isso que são chamados de iteradores à prova de falhas.

Iterator de CopyOnWriteArrayList é um exemplo de Iterator à prova de falhas e também iterador escrito por ConcurrentHashMap keySet também é um iterador à prova de falhas e nunca lança ConcurrentModificationException em Java.

Juned Ahsan
fonte
Não vejo o iterador ConcurrentHashMap trabalhando em clone () .. :( Algumas vezes ele refletirá algumas atualizações durante a iteração ..
Kanagavelu Sugumar
0

Este cenário diz respeito ao “processamento concorrente”, significa que mais de um usuário acessa o mesmo recurso. Em tal situação, um dos usuários tenta modificar aquele recurso que causa a 'ConcurrentProcessingException' porque nesse caso outro usuário obtém dados impróprios. Ambos os tipos se relacionam com esse tipo de situação.

Em termos simples,

Fail-Fast:

  • Os iteradores lançam imediatamente ConcurrentModificationException se houver modificação estrutural (adicionar, atualizar, excluir).
  • Exemplo: ArrayList, HashMap, TreeSet

À prova de falhas:

  • Aqui, os iteradores não lançam nenhuma exceção porque operam no clone da coleção, não no original. Portanto, eles são iteradores à prova de falhas.
  • Exemplo: CopyOnWriteArrayList, ConcurrentHashMap
Dhwanil Patel
fonte