Maison > Questions et réponses > le corps du texte
选自《阿里巴巴JAVA开发手册》
图1代码执行情况是:解释删除1这个元素不会报错,但是删除2这个元素报错了,这个情况如何解释?
大家讲道理2017-04-18 10:56:42
La source de l'erreur checkForComodification()
peut être connue grâce à l'erreur signalée. Si vous souhaitez éviter les erreurs, vous devez conserver modCount != expectedModCount
comme false
. list.remove(Object)
appellera la méthode fastRemove(int)
, et elle modifiera inévitablement modCount
à ce moment-là, et une erreur se produira à ce moment-là. Iterator<String> iterator = list.iterator()
; L'implémentation de cette méthode consiste à renvoyer une classe interne Itr
(cette classe est utilisée dans le processus d'itération), mais la raison pour laquelle cela iterator.remove()
ne provoque pas d'erreurs est due à la relation entre cette méthode et L'implémentation consiste à vérifier ArrayList.this.remove
avant de faire le checkForComodfication
réel et à faire remove
après expectedModCount = modCount
afin qu'aucune erreur ne se produise.
Itr.remove
Mise en œuvre
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
S'il y a quelque chose qui ne va pas, veuillez le signaler @ChaCha哥 @puliuyinyi
PHP中文网2017-04-18 10:56:42
Dans le cas d'un seul thread, lors de la suppression d'éléments lors du parcours de la liste, vous devez utiliser la méthode Remove d'Iterator au lieu de la méthode Remove de List, sinon une ConcurrentModificationException se produira. Imaginez simplement si un enseignant compte le nombre d'élèves dans toute la classe, et si les élèves ne respectent pas les règles et ne sortent pas et n'entrent pas, l'enseignant ne pourra certainement pas les compter.
Dans le cas du multi-threading, référez-vous à un de mes blogs : http://xxgblog.com/2016/04/02...
天蓬老师2017-04-18 10:56:42
Tout d'abord, cela implique des opérations multi-thread. Iterator ne prend pas en charge les opérations multi-thread. La classe List maintiendra une variable modCount en interne pour enregistrer le nombre de modifications
Exemple : code source ArrayList
protected transient int modCount = 0;
Chaque fois qu'un Iterator est généré, l'Iterator enregistrera le modCount. Chaque fois que la méthode next() est appelée, l'enregistrement sera comparé au modCount de la classe externe List. S'il s'avère inégal, un. une exception d'édition multithread sera levée.
Pourquoi fais-tu ça ? Je crois comprendre que vous avez créé un itérateur étroitement couplé au contenu de la collection à parcourir, ce qui signifie que le contenu de la collection correspondant à cet itérateur est le contenu actuel. Je ne veux absolument pas le faire dans mon cas. tri à bulles. Quand , il y a encore des threads qui insèrent des données dans ma collection, n'est-ce pas ? Java utilise donc ce mécanisme de traitement simple pour empêcher la collection d'être modifiée pendant le parcours.
Quant à savoir pourquoi supprimer "1" est suffisant, la raison réside dans la méthode hasNext() de foreach et de l'itérateur. Le sucre syntaxique de foreach est en fait
.while(itr.hasNext()){
itr.next()
}
Donc, chaque boucle exécutera hasNext() en premier, alors jetez un œil à la façon dont hasNext() d'ArrayList est écrit :
public boolean hasNext() {
return cursor != size;
}
cursor est une variable utilisée pour marquer la position de l'itérateur. La variable commence à 0 et effectue une opération +1 à chaque fois que next est appelé, donc :
Après que votre code supprime "1", size=1, curseur = 1, à ce moment hasNext() renvoie false et termine la boucle, donc votre itérateur n'appelle pas next pour trouver le deuxième élément, donc il n'y a aucun moyen de détecter modCount, donc il n'y aura pas d'exception de modification multi-thread
mais lorsque vous avez supprimé "2", l'itérateur a appelé next deux fois, à ce moment-là, size=1, curseur=2 et hasNext() a renvoyé true, donc l'itérateur a bêtement appelé next() à nouveau, ce qui a également déclenché If. modCount n'est pas égal, une exception de modification multithread sera levée.
Lorsque votre ensemble comporte trois éléments, vous constaterez comme par magie que la suppression de "1" lèvera une exception, mais la suppression de "2" ne posera pas de problème. La raison est liée à l'exécution du programme ci-dessus. L'ordre est cohérent. .
黄舟2017-04-18 10:56:42
Étant donné que le nombre dans la collection change lorsque vous ajoutez ou supprimez des éléments, des problèmes peuvent survenir lors du parcours. Par exemple, si une collection contient 10 éléments, elle doit être parcourue 10 fois. le nombre de traversées est incorrect, donc une erreur sera signalée
PHPz2017-04-18 10:56:42
Supprimez-les simplement dans l’ordre inverse. Quoi qu’il en soit, essayez de ne pas supprimer la liste. Vous pouvez ajouter une balise de suppression
伊谢尔伦2017-04-18 10:56:42
La description jaune dans le document est très intéressante.
Le résultat de l'exécution de cet exemple dépassera les attentes de tout le monde. Essayez donc de remplacer « 1 » par « 2 », cela aura-t-il le même résultat ?
Vous devez quand même regarder le code source de ArrayList
pour cela, vous le saurez d'un coup d'œil.
PHP中文网2017-04-18 10:56:42
ArrayList n'est pas thread-safe, ce qui signifie que vous modifiez la liste pendant le parcours.
ArrayList lèvera une exception de modification simultanée dans ce cas.