Comment éviter HashMap “ConcurrentModificationException” lors de la manipulation de valeurs de()` et `()` dans les threads simultanés?
Code:
J'ai une table de hachage
private Map<K, V> map = new HashMap<>();
Une méthode sera mis K-V paire en en appelant put(K,V)
.
L'autre méthode veut extraire un ensemble d'éléments aléatoires à partir de ses valeurs:
int size = map.size(); //size > 0
V[] value_array = map.values().toArray(new V[size]);
Random rand = new Random();
int start = rand.nextInt(size); int end = rand.nextInt(size);
//return value_array[start .. end - 1]
Les deux méthodes sont appelées dans deux différents threads simultanés.
Erreur:
J'ai eu un ConcurrentModificationException
erreur:
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$ValueIterator.next(Unknown Source)
at java.util.AbstractCollection.toArray(Unknown Source)
Il semble que la toArray()
méthode dans un thread est en fait une itération sur la table de hachage et un put()
modification dans d'autres thread se produit.
Question: Comment éviter de "ConcurrentModificationException" tout en utilisant une table de hachage.les valeurs de().toArray() et de la table de hachage.put() dans les threads simultanés?
Directement en évitant l'utilisation devalues().toArray()
dans la deuxième méthode est également OK.
map
dans un synchroniser bloc: synchronize(map){...}
synchronize(map){..}
devrait fonctionner (si vous l'appliquer partout). Les Collections.synchronizedMap ne fonctionne pas. voir docs.oracle.com/javase/7/docs/api/java/util/...OriginalL'auteur hengxin | 2014-10-29
Vous devez vous connecter pour publier un commentaire.
Vous devez fournir un certain niveau de synchronisation de sorte que l'appel à
put
est bloqué, tout letoArray
appel est en cours d'exécution, et vice-versa. Il y a desde deux approches simples:put
ettoArray
danssynchronized
blocs synchronisés sur le même verrouillage de l'objet (qui peut être la carte elle-même ou un autre objet).mettez votre carte dans un synchronisé carte à l'aide de
Collections.synchronizedMap()
Utiliser un
ConcurrentHashMap
au lieu d'unHashMap
.EDIT: Le problème avec l'aide de
Collections.synchronizedMap
est qu'une fois que l'appel àvalues()
retourne, la simultanéité de la protection disparaît. À ce stade, les appels àput()
ettoArray()
peut exécuter simultanément. UnConcurrentHashMap
a un peu le même problème, mais il peut encore être utilisé. À partir de la documentation pourConcurrentHashMap.les valeurs de()
:Merci. Cependant, j'ai lu certains commentaires qui ConcurrentHashMap ne résout pas nécessairement ConcurrentModificationException (mais ne parviennent pas à trouver la source de maintenant). Pourquoi faut-il travailler dans ce mon cas?
Vous avez besoin
values()
de travail multi-thread, et la Javadoc dit "Le point de vue de l'itérateur est un "faiblement cohérente" itérateur qui ne sera jamais jeter ConcurrentModificationException, et des garanties pour parcourir les éléments tels qu'ils existaient au moment de la construction de l'itérateur, et peut (mais n'est pas garanti) tenir compte de toutes modifications ultérieures de la construction.""peut (mais n'est pas garanti)". Si vous avez besoin plus strictes assurances, ajouter des blocs synchronisés pour tous vos HashMap accède à la place.
synchronizedMap
les plus susceptibles de ne pas travailler, voir les remarques à propos de l'itération dans le docs.oracle.com/javase/7/docs/api/java/util/...OriginalL'auteur Ted Hopp
Je voudrais utiliser ConcurrentHashMap au lieu d'une table de hachage et de le protéger contre simultané de la lecture et la modification par différents threads. Voir ci-dessous la mise en œuvre. Il n'est pas possible pour le fil 1 et le fil 2 à lire et à écrire en même temps. Lorsque le thread 1 est l'extraction des valeurs de Map à un tableau, tous les autres threads qui l'invoque, storeInMap(K, V) de suspendre et d'attendre sur la carte jusqu'à ce que le premier thread est terminé avec l'objet.
Note: je n'utilise pas de méthode synchronisée dans ce contexte; je ne suis pas complètement écarter la méthode synchronisée, mais je voudrais l'utiliser avec prudence. Une méthode synchronisée est en fait juste la syntaxe de sucre pour obtenir un verrou sur 'ce' et la détention pour la durée de la méthode, de sorte qu'il peut blesser le débit.
syncronized
blocs si vous utilisez déjà unConcurrentHashMap
?OriginalL'auteur Danny Ho