Question Quelle est la différence entre ConcurrentHashMap et Collections.synchronizedMap (Map)?


J'ai une carte qui doit être modifiée par plusieurs threads simultanément.

Il semble y avoir trois implémentations de cartes synchronisées différentes dans l'API Java:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

D'après ce que je comprends, Hashtable est une ancienne mise en œuvre (prolongeant l'obsolète Dictionary classe), qui a été adapté plus tard pour s'adapter à Map interface. Alors qu'il est synchronisé, il semble avoir sérieux problèmes d'évolutivité et est découragé pour de nouveaux projets.

Mais qu'en est-il des deux autres? Quelles sont les différences entre les cartes renvoyées par Collections.synchronizedMap(Map) et ConcurrentHashMaps? Lequel correspond à quelle situation?


523
2018-02-04 09:22


origine


Réponses:


Pour vos besoins, utilisez ConcurrentHashMap. Il permet la modification simultanée de la Map à partir de plusieurs threads sans avoir besoin de les bloquer. Collections.synchronizedMap(map) crée une carte bloquante qui dégradera les performances, mais assurera la cohérence (si elle est utilisée correctement).

Utilisez la deuxième option si vous devez assurer la cohérence des données, et chaque thread doit avoir une vue à jour de la carte. Utilisez la première si la performance est critique, et chaque thread insère uniquement des données sur la carte, avec des lectures moins fréquentes.


372
2018-02-04 09:32



╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║Is thread-safe ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

En ce qui concerne le mécanisme de verrouillage: Hashtable  verrouille l'objet, tandis que ConcurrentHashMap serrures seulement le seau.


200
2017-07-21 20:09



Les "problèmes d'évolutivité" pour Hashtable sont présents exactement de la même manière dans Collections.synchronizedMap(Map) - ils utilisent une synchronisation très simple, ce qui signifie qu'un seul thread peut accéder à la carte en même temps.

Cela ne pose pas vraiment problème lorsque vous avez des insertions et des recherches simples (sauf si vous le faites de manière extrêmement intensive), mais que cela pose un gros problème lorsque vous devez parcourir toute la carte, ce qui peut prendre beaucoup de temps. un thread fait cela, tous les autres doivent attendre s'ils veulent insérer ou rechercher quelque chose.

le ConcurrentHashMap utilise des techniques très sophistiquées pour réduire le besoin de synchronisation et permettre un accès en lecture parallèle par plusieurs threads sans synchronisation et, plus important encore, fournit un accès Iterator cela ne nécessite aucune synchronisation et permet même de modifier la carte pendant l'interaction (bien qu'elle ne garantisse pas si les éléments insérés pendant l'itération seront renvoyés).


127
2018-02-04 09:43



ConcurrentHashMap est préféré quand vous pouvez l'utiliser - bien qu'il nécessite au moins Java 5.

Il est conçu pour évoluer correctement lorsqu'il est utilisé par plusieurs threads. Les performances peuvent être légèrement inférieures lorsque un seul thread accède à la carte à la fois, mais nettement mieux lorsque plusieurs threads accèdent simultanément à la carte.

j'ai trouvé un entrée de blog qui reproduit une table de l'excellent livre Java Concurrency en pratique, que je recommande vivement.

Collections.synchronizedMap n'a de sens que si vous devez envelopper une carte avec d'autres caractéristiques, par exemple une carte ordonnée, comme un TreeMap.


31
2018-02-04 09:34



La principale différence entre ces deux est que ConcurrentHashMap verrouille uniquement la partie des données qui sont en cours de mise à jour alors que d'autres parties peuvent accéder à d'autres parties de données. cependant, Collections.synchronizedMap() verrouille toutes les données lors de la mise à jour, les autres threads ne peuvent accéder aux données que lorsque le verrou est libéré. S'il existe de nombreuses opérations de mise à jour et une petite quantité relative d'opérations de lecture, vous devez choisir ConcurrentHashMap.

Une autre différence est que ConcurrentHashMap ne conservera pas l'ordre des éléments dans la carte transmise. Il est similaire à HashMap lors du stockage des données. Il n'y a aucune garantie que l'ordre des éléments soit préservé. Tandis que Collections.synchronizedMap() conservera l'ordre des éléments de la carte transmise. Par exemple, si vous passez un TreeMap à ConcurrentHashMap, l'ordre des éléments dans le ConcurrentHashMap peut ne pas être le même que l'ordre dans le TreeMap, mais Collections.synchronizedMap() conservera l'ordre.

En outre, ConcurrentHashMap peut garantir qu'il n'y a pas ConcurrentModificationException jeté pendant qu'un thread met à jour la carte et qu'un autre thread traverse l'itérateur obtenu à partir de la carte. cependant, Collections.synchronizedMap() n'est pas garanti à ce sujet.

Il y a un post qui démontrent les différences de ces deux et aussi ConcurrentSkipListMap.


29
2017-11-16 15:53



Dans ConcurrentHashMap, le verrou est appliqué à un segment au lieu d'une carte entière. Chaque segment gère sa propre table de hachage interne. Le verrou est appliqué uniquement pour les opérations de mise à jour. Collections.synchronizedMap(Map) synchronise la carte entière.


12
2017-10-28 18:00



Comme d'habitude, il y a des compromis de concurrence - overhead - vitesse impliqués. Vous devez vraiment prendre en compte les exigences détaillées en matière de simultanéité de votre application pour prendre une décision, puis tester votre code pour voir s'il est suffisant.


11
2018-02-04 09:36



Vous avez raison à propos de HashTable, tu peux l'oublier.

Votre article mentionne le fait que HashTable et la classe d'encapsulation synchronisée fournissent une sécurité de thread de base en n'autorisant qu'un seul thread à la fois à accéder à la carte, ce n'est pas un vrai thread-safety puisque de nombreuses opérations complexes nécessitent une synchronisation supplémentaire, par exemple:

synchronized (records) {
  Record rec = records.get(id);
  if (rec == null) {
      rec = new Record(id);
      records.put(id, rec);
  }
  return rec;
}

Cependant, ne pense pas que ConcurrentHashMap est une alternative simple pour un HashMap avec un typique synchronized bloquer comme indiqué ci-dessus. Lis ce article pour mieux comprendre ses subtilités.


9
2018-02-04 09:38



Voici quelques-uns:

1) ConcurrentHashMap verrouille seulement une partie de Map mais SynchronizedMap verrouille tout MAp.
2) ConcurrentHashMap a de meilleures performances sur SynchronizedMap et plus évolutif.
3) En cas de lecteur multiple et d'écrivain unique ConcurrentHashMap est le meilleur choix.

Ce texte provient de Différence entre ConcurrentHashMap et hashtable en Java


7
2017-11-24 07:32



Nous pouvons obtenir la sécurité des threads en utilisant ConcurrentHashMap et synchronisedHashmap et Hashtable. Mais il y a beaucoup de différence si vous regardez leur architecture.

  1. synchronizedHashmap et Hashtable

Les deux maintiendront le verrou au niveau de l'objet. Donc, si vous voulez effectuer une opération comme put / get, vous devez d'abord acquérir le verrou. En même temps, les autres threads ne sont autorisés à effectuer aucune opération. Donc, à la fois, un seul thread peut fonctionner à ce sujet. Donc, le temps d'attente augmentera ici. Nous pouvons dire que la performance est relativement faible lorsque vous comparez avec ConcurrentHashMap.

  1. ConcurrentHashMap

Il maintiendra le verrou au niveau du segment. Il a 16 segments et maintient le niveau de concurrence comme 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 verrou. Ainsi, n'importe quel nombre de threads peut effectuer une opération get sur celui-ci.

Si thread1 veut effectuer une opération put dans le segment 2 et que thread2 veut effectuer une opération put sur le segment 4, alors il est autorisé ici. Moyens, 16 threads peuvent effectuer une opération de mise à jour (put / delete) sur ConcurrentHashMap à la fois.

Alors que le temps d'attente sera moins ici. Par conséquent, les performances sont relativement meilleures que synchronizedHashmap et Hashtable.


7
2018-03-09 13:12