Quelle est la différence entre l'utilisation de la classe wrapper, SynchronizedMap
, sur un HashMap
et ConcurrentHashMap
? Est-ce simplement pouvoir modifier le HashMap
tout en l'itérant (ConcurrentHashMap
)?
HashMap
: synchronisé
Chaque méthode est synchronisée à l'aide d'un verrou au niveau de l'objet. Donc, les méthodes get et put sur synchMap acquièrent un verrou.
Verrouiller toute la collection est une surcharge de performances. Tant qu'un thread maintient le verrou, aucun autre thread ne peut utiliser la collection.
ConcurrentHashMap
a été introduit dans JDK 5.
Il n'y a pas de verrouillage au niveau de l'objet. Le verrouillage est beaucoup plus fin. Pour un ConcurrentHashMap
, les verrous peuvent être au niveau d'un compartiment hashmap.
L'effet du verrouillage de niveau inférieur est que vous pouvez avoir des lecteurs et des écrivains simultanés, ce qui n'est pas possible pour les collections synchronisées. Cela conduit à beaucoup plus d'évolutivité.
ConcurrentHashMap
ne lance pas une ConcurrentModificationException
si un thread tente de le modifier pendant qu'un autre itère dessus.
Cet article Java 7: HashMap vs ConcurrentHashMap est une très bonne lecture. Hautement recommandé.
La réponse courte:
Les deux cartes sont des implémentations thread-safe de l'interface Map
. ConcurrentHashMap
est implémenté pour un débit plus élevé dans les cas où une simultanéité élevée est attendue.
Le article de Brian Goetz sur l'idée derrière ConcurrentHashMap
est une très bonne lecture. Hautement recommandé.
ConcurrentHashMap
est thread-safe sans synchronisation de la carte entière. Les lectures peuvent être très rapides lorsque l'écriture est effectuée avec un verrou.
Nous pouvons atteindre la sécurité des threads en utilisant à la fois ConcurrentHashMap et synchronizedHashmap. Mais il y a beaucoup de différence si vous regardez leur architecture.
Cela maintiendra le verrou au niveau de l'objet. Donc, si vous souhaitez effectuer une opération telle que put/get, vous devez d'abord acquérir le verrou. Dans le même temps, les autres threads ne sont autorisés à effectuer aucune opération. Donc, à la fois, un seul thread peut fonctionner sur cela. Donc, le temps d'attente augmentera ici. Nous pouvons dire que les performances sont relativement faibles lorsque vous comparez avec ConcurrentHashMap.
Il maintiendra le verrou au niveau du segment. Il comporte 16 segments et maintient le niveau de concurrence de 16 par défaut. Donc, à la fois, 16 threads peuvent fonctionner sur ConcurrentHashMap. De plus, l'opération de lecture ne nécessite pas de verrouillage. Donc, n'importe quel nombre de threads peuvent effectuer une opération get sur celui-ci.
Si thread1 veut effectuer une opération de vente dans le segment 2 et que thread2 souhaite effectuer une opération de vente sur le segment 4, il est autorisé à le faire ici. Cela signifie que 16 threads peuvent effectuer une opération de mise à jour (insertion/suppression) sur ConcurrentHashMap à la fois.
Alors que le temps d'attente sera moins ici. Par conséquent, les performances sont relativement meilleures que synchronizedHashmap.
Les deux sont une version synchronisée de HashMap, avec des fonctionnalités différentes et une structure interne différente.
ConcurrentHashMap est constitué de segments internes pouvant être considérés comme des HashMaps indépendants Conceptuellement . Tous ces segments peuvent être verrouillés par des threads distincts lors d'exécutions simultanées élevées . de ConcurrentHashMap sans se bloquer/attendre les uns des autres . Ceci est implémenté pour un débit plus élevé.
tandis que
Collections.synchronizedMap () , nous obtenons une version synchronisée de HashMap à laquelle on accède de manière bloquante. Cela signifie que si plusieurs threads tentent d'accéder à synchronizedMap en même temps, ils seront autorisés à obtenir/mettre des paires clé-valeur une par une de manière synchronisée.
ConcurrentHashMap
utilise un mécanisme de verrouillage à grain plus fin, appelé lock stripping
, pour permettre un plus grand accès partagé. De ce fait, il offre une meilleure concurrence et une évolutivité .
Les itérateurs renvoyés pour ConcurrentHashMap
sont également faiblement cohérent au lieu de technique d'échec rapide utilisé par Synchronized HashMap.
Les méthodes sur SynchronizedMap
maintiennent le verrou sur l'objet, alors que dans ConcurrentHashMap
, il existe un concept de "bande de verrouillage" dans lequel les verrous sont maintenus sur des compartiments du contenu. Ainsi, l'évolutivité et les performances ont été améliorées.
ConcurrentHashMap:
1) Les deux cartes sont des implémentations thread-safe de l'interface Map.
2) ConcurrentHashMap est implémenté pour un débit plus élevé dans les cas où une simultanéité élevée est attendue.
3) Il n'y a pas de verrouillage au niveau de l'objet.
Carte de hachage synchronisée:
1) Chaque méthode est synchronisée à l'aide d'un verrou au niveau de l'objet.
Un test de performance simple pour ConcurrentHashMap vs Synchronized HashMap . Le flux de test appelle put
dans un thread et get
dans trois threads sur Map
simultanément. Comme @trshiv l'a dit, ConcurrentHashMap a un débit et une vitesse plus élevés pour les opérations de lecture sans verrouillage. Le résultat est que, lorsque l'opération a dépassé 10^7
, ConcurrentHashMap est 2x
plus rapide que Synchronized HashMap.
Selon le document Java
Hashtable et Collections.synchronizedMap (nouveaux HashMap ()) sont synchronisé. Mais ConcurrentHashMap est "simultané".
Une collection simultanée est sécurisée pour les threads, mais non régie par un seul verrou d'exclusion.
Dans le cas particulier de ConcurrentHashMap, il permet en toute sécurité un nombre quelconque de lectures simultanées ainsi qu'un nombre ajustable de écrit simultané. Les classes "synchronisées" peuvent être utiles lorsque vous avez besoin de pour empêcher tout accès à une collection via un seul verrou, au niveau du fichier frais de moins bonne évolutivité.
Dans les autres cas dans lesquels plusieurs les threads doivent accéder à une collection commune, "concurrente" les versions sont normalement préférables. Et les collections non synchronisées sont préférable lorsque les collections ne sont pas partagées ou sont accessibles seulement en tenant d'autres serrures.
ConcurrentHashMapautorise l'accès simultané aux données. Toute la carte est divisée en segments.
Opération de lecture get(Object key)
n'est pas synchronisé même au niveau du segment.
Mais écrivez des opérations à savoir. remove(Object key), get(Object key)
acquiert un verrou au niveau du segment. Seule une partie de la carte entière est verrouillée, les autres threads peuvent toujours lire les valeurs de différents segments, sauf le verrouillé.
SynchronizedMap d’autre part, acquiert un verrou au niveau de l’objet. Tous les threads doivent attendre le thread actuel indépendamment de l'opération (lecture/écriture).