7
votes

Java Collections.sort () Manquant ConcurrentModificationException

J'ai trébuché sur cet étrange bug. On dirait que collections.sort () ne modifie pas la liste triée d'une manière qui permet une détection de modifications simultanées lors de l'itération sur la même liste. Exemple de code: xxx

sorties xxx

on pourrait s'attendre à un ConcurrentModificationException , mais il n'est pas en cours de soulevée et Le code fonctionne bien que cela ne soit pas.


3 commentaires

Vous n'avez pas deux threads; Il n'y a pas de concurrence (qui est vraiment à quoi cette exception était censée garder). Même dans ... Notez que le comportement de l'échec-rapide d'un itérateur ne peut pas être garanti tel qu'il est, d'une manière générale, impossible de faire des garanties difficiles en présence de modifications simultanées non synchronisées. Les itérateurs d'échec-Fast lancent une exception exceptionnelle sur une base de meilleur effort. Par conséquent, il serait faux d'écrire un programme qui dépendait de cette exception pour son exactitude: le comportement échec-rapide des itérateurs doit être utilisé uniquement pour détecter les bogues.


Eh bien, vous obtenez cette exception si vous ajoutez un élément à la liste (dans le même fil). Cela n'a pas de sens pour moi pourquoi l'on ajoute des éléments à la liste une opération illégale, mais chanterait la liste n'est pas ...


Parce que ce n'est pas Modification structurellement la liste , les nœuds qui composent la liste sont toujours là et ils n'ont même pas changé de commande. Votre itérateur n'est pas affecté par une valeur contenue dans les nœuds changeant. En bref, il n'est vraiment pas censé vous protéger de vous-même.


3 Réponses :


4
votes

Pourquoi lancerait-il ConcurrentModificationException lorsque vous n'ayez pas ajouté / supprimer des éléments de votre collection tout en itération?

Notez que ConcurrentModificationException ne se produirait que lorsqu'un nouvel élément est ajouté à votre collection ou enlevez de votre collection en itération. c'est-à-dire que lorsque votre collection est modifiée de manière structurelle.

(les modifications structurelles sont celles qui changent la taille de cette liste, ou sinon la perturber de manière aussi la mode que les itérations en cours peut donner des résultats incorrects.)

Trier ne modifierait pas de manière structurelle votre collection, tout ce qu'il fait est de modifier la commande. Le code ci-dessous lancerait ConcurrentModificationException car il ajoutait un élément supplémentaire dans la collection tout en itération. xxx

Si vous regardez la source de la méthode de tri < href = "http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/collections.java" rel = "nofollow"> collections classe, elle ne lance pas ConcurrentModificationException .

Cette implémentation décharge la liste spécifiée dans un tableau, trie le Array et compter sur la liste réinitialisant chaque élément de la position correspondante dans le tableau. Cela évite le journal n2 (n) performance qui résulterait de la tentative de trier une liste liée dans Place. xxx

extrait du livre Generics et collections Java :

La politique des itérateurs pour les collections Java 2 est d'échouer rapide, comme décrit à la section 11.1: chaque fois qu'ils accèdent au support collection, ils vérifient la modification structurelle (qui, dans général, signifie que les éléments ont été ajoutés ou supprimés de la collection). S'ils détectent la modification structurelle, ils échouent immédiatement, jetant une exception concurrente plutôt que continuer à tenter de parcourir la collection modifiée avec Résultats imprévisibles.


4 commentaires

+1. de la position correspondante dans le tableau


Je sais. J'ai vérifié ce code aussi. Je trouve toujours qu'il devrait y avoir un tel drapeau est défini dans trier () .


point équitable. Donc, c'est le fameux "C'est une fonctionnalité, pas un bogue". Une façon de résoudre le ... :-) Je ne vois toujours pas vraiment comment l'ajout est considéré comme un changement structurel tout en mélangeant son contenu n'est pas.


@Daniel Vérifiez ici dans la source ArrayList pour quoi MOYENS DE MODIFIÉ STRANTILISÉE dans le CODE Sevoir. GrepCode. Com / Fichier / Repository.GrepCode.com / Java / Root / JDK / Ouvrir JDK / ...



1
votes

Parler de fonctionnalités Je ne vois pas pourquoi il ne faut pas lancer ConcurrentModificationException . Mais selon la documentation, l'itérateur jette l'exception lorsqu'il remarque que la modification structurelle et la modification structurelle est défini comme:

Les modifications structurelles sont celles qui changent la taille de la liste, ou sinon la perturber de manière aussi la mode que les itérations en cours peut donner des résultats incorrects.

Je pense qu'il existe un argument pour affirmer que réorganiser réorganiser les éléments provoque l'itérateur de donner des résultats incorrects, mais je n'ai pas vérifié quels sont les résultats obtenus pour que l'itérateur soit défini.

Parler de la mise en œuvre, il est facile de voir pourquoi il ne: VOIR LA SOURCE POUR ArrayList et collections :


0 commentaires

1
votes

Pour Android, cela dépend des versions API. De l'API 26, Collections # Trier (liste , comparateur ) appelle en fait Liste # Trier (comparateur ) . Donc, si vous triez ArrayList , vous pouvez obtenir ConcurrentModificationException selon que vous avez modifié la liste dans un autre fil. Voici le code source de java / util / arraylist.java qui jette l'exception: xxx


0 commentaires