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

607

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

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, Hashtableest une ancienne implémentation (extension de la Dictionaryclasse obsolète ), qui a été adaptée plus tard pour s'adapter à l' Mapinterface. Bien qu'il soit synchronisé, il semble avoir de graves problèmes d'évolutivité et est déconseillé pour les 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? Laquelle correspond à quelle situation?

Henning
la source
7
@SmilesinaJar Le lien est actuellement rompu, voici une copie archivée de cet article: Pourquoi ConcurrentHashMap est meilleur que Hashtable et tout aussi bon qu'un HashMap
informatik01
2
IBM: Comment ConcurrentHashMap offre une concurrence plus élevée sans compromettre la sécurité des threads @ ibm.com/developerworks/java/library/j-jtp08223/…
pramodc84
Pour info, Java 6 ConcurrentSkipListMapest une autre Mapimplémentation thread-safe . Conçu pour être hautement simultané sous charge, utilisant l' algorithme Skip List .
Basil Bourque

Réponses:

423

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

Utilisez la deuxième option si vous devez garantir la cohérence des données et que chaque thread doit avoir une vue à jour de la carte. Utilisez le premier si les performances sont critiques et que chaque thread insère uniquement des données dans la carte, les lectures ayant lieu moins fréquemment.

Yuval Adam
la source
8
En regardant le code source, la carte synchronisée n'est qu'une implémentation avec un mutex (blocage) tandis que le ConcurrentHashMap est plus complexe pour gérer les accès simultanés
Vinze
123
Veuillez également noter que ConcurrentHashMap n'autorise pas les clés ou les valeurs nulles. Ce ne sont donc PAS des alternatives égales d'une carte synchronisée.
onejigtwojig
5
@AbdullahShaikh Le problème soulevé dans cet article a été corrigé dans Java 7 et de nouvelles améliorations ont été apportées dans Java 8.
pulse0ne
5
@hengxin: dès que vous effectuez une opération consistant en plusieurs requêtes ou mises à jour de la carte ou lorsque vous parcourez la carte, vous devez synchroniser manuellement sur la carte pour garantir la cohérence. Les cartes synchronisées garantissent la cohérence uniquement pour des opérations uniques (invocations de méthode) sur la carte, ce qui la rend plus souvent sans valeur car la plupart des opérations réelles ne sont pas triviales, vous devez donc synchroniser manuellement de toute façon.
Holger
241
╔═══════════════╦═══════════════════╦═══════════════════╦═════════════════════╗
║   Property    ║     HashMap       ║    Hashtable      ║  ConcurrentHashMap  ║
╠═══════════════╬═══════════════════╬═══════════════════╩═════════════════════╣ 
║      Null     ║     allowed       ║              not allowed                ║
║  values/keys  ║                   ║                                         ║
╠═══════════════╬═══════════════════╬═════════════════════════════════════════╣
║ Thread-safety ║                   ║                                         ║
║   features    ║       no          ║                  yes                    ║
╠═══════════════╬═══════════════════╬═══════════════════╦═════════════════════╣
║     Lock      ║       not         ║ locks the whole   ║ locks the portion   ║        
║  mechanism    ║    applicable     ║       map         ║                     ║ 
╠═══════════════╬═══════════════════╩═══════════════════╬═════════════════════╣
║   Iterator    ║               fail-fast               ║ weakly consistent   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Concernant le mécanisme de verrouillage: Hashtable verrouille l'objet , tandis que neConcurrentHashMap verrouille que le seau .

Sergii Shevchyk
la source
13
Hashtablene verrouille pas une partie de la carte. Regardez l'implémentation. Il utilise une synchronizedclé sans verrou fourni, ce qui signifie qu'il se verrouille entièrement hashtableà chaque opération.
RMachnik
6
Qu'en est-il du synchronizedMap?
Samuel Edwin Ward
3
Le comportement de Collections.syncronizedMap est similaire à la carte de support, sauf que toutes les méthodes sont thread-safe
Sergii Shevchyk
5
Je voudrais imprimer le tableau et le vendre pour 5 $ chacun;). Good one @shevchyk
realPK
Modifié: ni l'un ni l'autre ne sont entièrement thread-safe. C'est un peu trompeur pour les nouveaux développeurs. Voir: ibm.com/developerworks/java/library/j-jtp07233/index.html pour comprendre que même ConcurrentHashMap n'est pas entièrement protégé contre les threads des races de données externes. (par exemple: 1 thread supprime une valeur et un autre essaie plus tard de vérifier si elle est présente et de la mettre dans le cas contraire. Il s'agit d'une condition de concurrence entre les données et cela signifie toujours que malgré l'utilisation d'un "ConcurrentHashMap", vous n'êtes pas soulagé de tous les problèmes de sécurité des threads.
Zombies
142

Les «problèmes d'évolutivité» pour Hashtablesont présents exactement de la même manière 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.

Ce n'est pas vraiment un problème lorsque vous avez des insertions et des recherches simples (à moins que vous ne le fassiez de manière extrêmement intensive), mais devient un gros problème lorsque vous devez parcourir toute la carte, ce qui peut prendre beaucoup de temps pour une grande carte - tout en un thread fait cela, tous les autres doivent attendre s'ils veulent insérer ou rechercher quoi que ce soit.

Il ConcurrentHashMaputilise 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 Iteratorqui ne nécessite aucune synchronisation et permet même de modifier la carte pendant l'interaction (bien qu'il ne garantisse pas si ou les éléments insérés lors de l'itération ne seront pas retournés).

Michael Borgwardt
la source
4
Voilà ce que je voulais! :) L'itérateur non synchronisé n'est que pure douceur! Merci pour l'info! :) (:
Kounavi
Excellente réponse ... mais cela signifie-t-il que lors de la récupération, le thread ne recevra pas les dernières mises à jour car les threads de lecture ne sont pas synchronisés.
MrA
@MrA: Posez-vous des questions sur ConcurrentHashMap? Et qu'entendez-vous par «récupération»?
Michael Borgwardt
4
@Michael Borgwardt pour ConcurrentHashmap par exemple. supposons qu'il existe plusieurs threads. certains mettent à jour la carte et certains obtiennent des données de cette même carte. Donc, dans ce scénario, lorsque les threads tentent de lire, il est garanti qu'ils obtiendront les dernières données mises à jour, car les threads de lecture n'ont pas besoin de verrouiller.
MrA
35

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

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

J'ai trouvé une entrée de blog qui reproduit un tableau de l'excellent livre Java Concurrency In Practice , que je recommande vivement.

Collections.synchronizedMap n'a de sens que si vous avez besoin d'envelopper une carte avec d'autres caractéristiques, peut-être une sorte de carte ordonnée, comme un TreeMap.

Bill Michell
la source
2
Ouais - semble que je mentionne ce livre dans toutes les autres réponses que je fais!
Bill Michell
Le lien @BillMichell est rompu
@Govinda Désactivez javascript avant d'accéder au lien. L'entrée de blog est toujours là!
Bill Michell
32

La principale différence entre ces deux est que ConcurrentHashMapne verrouillera qu'une partie des données qui sont mises à jour tandis que d'autres parties de données sont accessibles par d'autres threads. 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 un nombre relativement faible d'opérations de lecture, vous devez choisir ConcurrentHashMap.

Une autre différence est également que ConcurrentHashMapcela ne préservera pas l'ordre des éléments dans la carte transmise. Il est similaire au HashMapstockage des données. Il n'y a aucune garantie que l'ordre des éléments est préservé. While 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 ConcurrentHashMappeut ne pas être le même que l'ordre dans le TreeMap, mais Collections.synchronizedMap()préservera l'ordre.

De plus, ConcurrentHashMappeut garantir qu'il n'y a pas de ConcurrentModificationExceptionlevée 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 poste qui démontre les différences de ces deux et aussi le ConcurrentSkipListMap.

PixelsTech
la source
13

Carte synchronisée:

La carte synchronisée n'est pas non plus très différente de Hashtable et offre des performances similaires dans les programmes Java simultanés. La seule différence entre Hashtable et SynchronizedMap est que SynchronizedMap n'est pas un héritage et vous pouvez encapsuler n'importe quelle carte pour créer sa version synchronisée à l'aide de la méthode Collections.synchronizedMap ().

ConcurrentHashMap:

La classe ConcurrentHashMap fournit une version simultanée du HashMap standard. Il s'agit d'une amélioration de la fonctionnalité synchronizedMap fournie dans la classe Collections.

Contrairement à la table de hachage et à la carte synchronisée, il ne verrouille jamais la carte entière, mais divise la carte en segments et le verrouillage est effectué sur ceux-ci. Il fonctionne mieux si le nombre de threads de lecture est supérieur au nombre de threads d'écriture.

ConcurrentHashMap par défaut est séparé en 16 régions et des verrous sont appliqués. Ce nombre par défaut peut être défini lors de l'initialisation d'une instance ConcurrentHashMap. Lors de la définition de données dans un segment particulier, le verrouillage de ce segment est obtenu. Cela signifie que deux mises à jour peuvent toujours s'exécuter simultanément en toute sécurité si elles affectent chacune des compartiments distincts, minimisant ainsi les conflits de verrouillage et maximisant ainsi les performances.

ConcurrentHashMap ne lève pas d'exception ConcurrentModificationException

ConcurrentHashMap ne lève pas d'exception ConcurrentModificationException si un thread essaie de le modifier pendant qu'un autre l'itère

Différence entre synchornizedMap et ConcurrentHashMap

Collections.synchornizedMap (HashMap) renverra une collection qui est presque équivalente à Hashtable, où chaque opération de modification sur Map est verrouillée sur l'objet Map tandis que dans le cas de ConcurrentHashMap, la sécurité des threads est obtenue en divisant la carte entière en une partition différente en fonction du niveau de concurrence et verrouiller uniquement une partie particulière au lieu de verrouiller toute la carte.

ConcurrentHashMap n'autorise pas les clés nulles ou les valeurs nulles tandis que HashMap synchronisé autorise une clé nulle.

Liens similaires

Link1

Link2

Comparaison des performances

Ramesh Papaganti
la source
12

Comme d'habitude, il y a des compromis simultanés - frais généraux - vitesse impliqués. Vous devez vraiment prendre en compte les exigences détaillées de concurrence de votre application pour prendre une décision, puis tester votre code pour voir s'il est assez bon.

Zach Scrivena
la source
12

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.

Satish
la source
pouvez-vous jeter un œil à stackoverflow.com/questions/48579060/… ?
gstackoverflow
9

Vous avez raison HashTable, vous pouvez l’oublier.

Votre article mentionne le fait que, même si HashTable et la classe wrapper synchronisé offrent une sécurité de thread de base en n'autorisant qu'un thread à la fois à accéder à la carte, ce n'est pas une "vraie" sécurité de thread car de nombreuses opérations composées nécessitent toujours une synchronisation supplémentaire, par exemple. exemple:

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

Cependant, ne pensez pas que ce ConcurrentHashMapsoit une alternative simple pour un HashMapavec un synchronizedbloc typique comme indiqué ci-dessus. Lisez cet article pour mieux comprendre ses subtilités.

eljenso
la source
7

En voici peu:

1) ConcurrentHashMap verrouille uniquement une partie de la carte mais SynchronizedMap verrouille la totalité du 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 la différence entre ConcurrentHashMap et la table de hachage en Java

Raj
la source
7

Nous pouvons garantir la sécurité des threads en utilisant ConcurrentHashMap et synchronizedHashmap 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 souhaitez effectuer une opération comme 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. Le temps d'attente augmentera donc ici. Nous pouvons dire que les performances sont relativement faibles lorsque vous comparez avec ConcurrentHashMap.

  1. ConcurrentHashMap

Il maintiendra le verrou au niveau du segment. Il a 16 segments et maintient le niveau d'accès simultané à 16 par défaut. Ainsi, à la fois, 16 threads peuvent fonctionner sur ConcurrentHashMap. De plus, l'opération de lecture ne nécessite pas de verrou. Ainsi, un nombre illimité 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 thread2 veut effectuer une opération de vente sur le segment 4, cela est autorisé ici. Signifie que 16 threads peuvent effectuer une opération de mise à jour (put / delete) sur ConcurrentHashMap à la fois.

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

Sumanth Varada
la source
1
,1. que se passe-t-il si plusieurs threads tentent de modifier le même bloc? 2. Que se passe-t-il si, disons, deux threads essaient de lire les données du même bloc alors qu'un autre thread écrit des données en même temps?
prnjn
6

ConcurrentHashMap

  • Vous devez utiliser ConcurrentHashMap lorsque vous avez besoin d'une concurrence très élevée dans votre projet.
  • Il est thread-safe sans synchroniser toute la carte.
  • Les lectures peuvent se produire très rapidement tandis que l'écriture se fait avec un verrou.
  • Il n'y a pas de verrouillage au niveau de l'objet.
  • Le verrouillage est à une granularité beaucoup plus fine au niveau du compartiment de hachage.
  • ConcurrentHashMap ne lève pas d'exception ConcurrentModificationException si un thread essaie de le modifier pendant qu'un autre l'itère.
  • ConcurrentHashMap utilise une multitude de verrous.

SynchronizedHashMap

  • Synchronisation au niveau de l'objet.
  • Chaque opération de lecture / écriture doit acquérir un verrou.
  • Le verrouillage de toute la collection est une surcharge de performance.
  • Cela donne essentiellement accès à un seul thread à la carte entière et bloque tous les autres threads.
  • Cela peut provoquer des conflits.
  • SynchronizedHashMap renvoie Iterator, qui échoue rapidement en cas de modification simultanée.

la source

Premraj
la source
4

ConcurrentHashMap est optimisé pour un accès simultané.

Les accès ne verrouillent pas la carte entière mais utilisent une stratégie plus fine, ce qui améliore l'évolutivité. Il existe également des améliorations fonctionnelles spécifiquement pour l'accès simultané, par exemple des itérateurs simultanés.

starblue
la source
4

Il existe une fonctionnalité essentielle à noter ConcurrentHashMapautre que la fonctionnalité de concurrence qu'il fournit, qui est l' itérateur de sécurité . J'ai vu des développeurs utiliser ConcurrentHashMapsimplement parce qu'ils voulaient modifier le jeu d'entrées - mettre / supprimer tout en itérant dessus. Collections.synchronizedMap(Map)ne fournit pas fail-safe iterator mais il fournit échec rapide iterator à la place. les itérateurs à échec rapide utilisent un instantané de la taille de la carte qui ne peut pas être modifiée pendant l'itération.

hi.nitish
la source
3
  1. Si la cohérence des données est très importante - Utilisez Hashtable ou Collections.synchronizedMap (Map).
  2. Si la vitesse / les performances sont très importantes et que la mise à jour des données peut être compromise - Utilisez ConcurrentHashMap.
Shivam Maharshi
la source
2

En général, si vous souhaitez utiliser le ConcurrentHashMapassurez-vous que vous êtes prêt à manquer les «mises à jour»
(c'est-à-dire que l'impression du contenu du HashMap ne garantit pas qu'il imprimera la carte à jour) et utilisez des API comme CyclicBarrierpour assurer la cohérence à travers votre programme. cycle de la vie.

Kounavi
la source
1

La méthode Collections.synchronizedMap () synchronise toutes les méthodes du HashMap et le réduit efficacement à une structure de données où un thread peut entrer à la fois car il verrouille chaque méthode sur un verrou commun.

Dans ConcurrentHashMap, la synchronisation se fait un peu différemment. Plutôt que de verrouiller chaque méthode sur un verrou commun, ConcurrentHashMap utilise un verrou séparé pour des compartiments distincts, verrouillant ainsi uniquement une partie de la carte. Par défaut, il y a 16 compartiments et également des verrous séparés pour des compartiments séparés. Le niveau de concurrence par défaut est donc 16. Cela signifie théoriquement à tout moment que 16 threads peuvent accéder à ConcurrentHashMap s'ils vont tous dans des compartiments séparés.

infoj
la source
1

ConcurrentHashMap a été présenté comme une alternative à Hashtable dans Java 1.5 dans le cadre du package de concurrence. Avec ConcurrentHashMap, vous avez un meilleur choix non seulement s'il peut être utilisé en toute sécurité dans l'environnement multithread simultané, mais offre également de meilleures performances que Hashtable et synchronizedMap. ConcurrentHashMap fonctionne mieux car il verrouille une partie de la carte. Il permet des opérations de lecture simultanée et en même temps maintient l'intégrité en synchronisant les opérations d'écriture.

Comment ConcurrentHashMap est implémenté

ConcurrentHashMap a été développé comme alternative à Hashtable et prend en charge toutes les fonctionnalités de Hashtable avec des capacités supplémentaires, appelées niveau de concurrence. ConcurrentHashMap permet à plusieurs lecteurs de lire simultanément sans utiliser de blocs. Cela devient possible en séparant la carte en différentes parties et en ne bloquant qu'une partie de la carte dans les mises à jour. Par défaut, le niveau de concurrence est 16, donc la carte est divisée en 16 parties et chaque partie est gérée par un bloc séparé. Cela signifie que 16 threads peuvent fonctionner avec Map simultanément, s'ils fonctionnent avec différentes parties de Map. Il rend ConcurrentHashMap extrêmement productif et ne diminue pas la sécurité des threads.

Si vous êtes intéressé par certaines fonctionnalités importantes de ConcurrentHashMap et quand vous devez utiliser cette réalisation de Map - Je viens de mettre un lien vers un bon article - Comment utiliser ConcurrentHashMap en Java

Oleg Poltoratskii
la source
0

En plus de ce qui a été suggéré, je voudrais publier le code source lié à SynchronizedMap .

Pour sécuriser un Mapthread, nous pouvons utiliserCollections.synchronizedMap instruction et saisir l'instance de carte comme paramètre.

L'implémentation de synchronizedMapdans Collectionsest comme ci-dessous

   public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
        return new SynchronizedMap<>(m);
    }

Comme vous pouvez le voir, l' Mapobjet d' entrée est encapsulé par l' SynchronizedMapobjet.
Examinons la mise en œuvre de SynchronizedMap,

 private static class SynchronizedMap<K,V>
        implements Map<K,V>, Serializable {
        private static final long serialVersionUID = 1978198479659022715L;

        private final Map<K,V> m;     // Backing Map
        final Object      mutex;        // Object on which to synchronize

        SynchronizedMap(Map<K,V> m) {
            this.m = Objects.requireNonNull(m);
            mutex = this;
        }

        SynchronizedMap(Map<K,V> m, Object mutex) {
            this.m = m;
            this.mutex = mutex;
        }

        public int size() {
            synchronized (mutex) {return m.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return m.isEmpty();}
        }
        public boolean containsKey(Object key) {
            synchronized (mutex) {return m.containsKey(key);}
        }
        public boolean containsValue(Object value) {
            synchronized (mutex) {return m.containsValue(value);}
        }
        public V get(Object key) {
            synchronized (mutex) {return m.get(key);}
        }

        public V put(K key, V value) {
            synchronized (mutex) {return m.put(key, value);}
        }
        public V remove(Object key) {
            synchronized (mutex) {return m.remove(key);}
        }
        public void putAll(Map<? extends K, ? extends V> map) {
            synchronized (mutex) {m.putAll(map);}
        }
        public void clear() {
            synchronized (mutex) {m.clear();}
        }

        private transient Set<K> keySet;
        private transient Set<Map.Entry<K,V>> entrySet;
        private transient Collection<V> values;

        public Set<K> keySet() {
            synchronized (mutex) {
                if (keySet==null)
                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
                return keySet;
            }
        }

        public Set<Map.Entry<K,V>> entrySet() {
            synchronized (mutex) {
                if (entrySet==null)
                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
                return entrySet;
            }
        }

        public Collection<V> values() {
            synchronized (mutex) {
                if (values==null)
                    values = new SynchronizedCollection<>(m.values(), mutex);
                return values;
            }
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return m.equals(o);}
        }
        public int hashCode() {
            synchronized (mutex) {return m.hashCode();}
        }
        public String toString() {
            synchronized (mutex) {return m.toString();}
        }

        // Override default methods in Map
        @Override
        public V getOrDefault(Object k, V defaultValue) {
            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
        }
        @Override
        public void forEach(BiConsumer<? super K, ? super V> action) {
            synchronized (mutex) {m.forEach(action);}
        }
        @Override
        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
            synchronized (mutex) {m.replaceAll(function);}
        }
        @Override
        public V putIfAbsent(K key, V value) {
            synchronized (mutex) {return m.putIfAbsent(key, value);}
        }
        @Override
        public boolean remove(Object key, Object value) {
            synchronized (mutex) {return m.remove(key, value);}
        }
        @Override
        public boolean replace(K key, V oldValue, V newValue) {
            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
        }
        @Override
        public V replace(K key, V value) {
            synchronized (mutex) {return m.replace(key, value);}
        }
        @Override
        public V computeIfAbsent(K key,
                Function<? super K, ? extends V> mappingFunction) {
            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
        }
        @Override
        public V computeIfPresent(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
        }
        @Override
        public V compute(K key,
                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.compute(key, remappingFunction);}
        }
        @Override
        public V merge(K key, V value,
                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
        }

        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

Ce SynchronizedMapqui peut être résumé comme l'ajout d'un verrou unique à la méthode principale de l' Mapobjet d' entrée . Toutes les méthodes gardées par le verrou ne sont pas accessibles par plusieurs threads en même temps. Cela signifie que les opérations normales comme putet getpeuvent être exécutées par un seul thread en même temps pour toutes les données duMap objet.

Cela fait Map thread d'objet sûr maintenant mais les performances peuvent devenir un problème dans certains scénarios.

La mise en œuvre ConcurrentMapest beaucoup plus compliquée, nous pouvons nous référer à Construire un meilleur HashMap pour plus de détails. En un mot, il est mis en œuvre en tenant compte à la fois du thread safe et des performances.

Eugène
la source