Jaka jest różnica między ConcurrentHashMap i Collections.synchronizedMap (mapa)?

607

Mam mapę, która ma być jednocześnie modyfikowana przez kilka wątków.

Wydaje się, że istnieją trzy różne zsynchronizowane implementacje map w API Java:

  • Hashtable
  • Collections.synchronizedMap(Map)
  • ConcurrentHashMap

Z tego, co rozumiem, Hashtablejest stara implementacja (rozszerzająca przestarzałą Dictionaryklasę), która została później dostosowana do Mapinterfejsu. Chociaż jest zsynchronizowany, wydaje się, że ma poważne problemy ze skalowalnością i jest zniechęcany do nowych projektów.

Ale co z pozostałymi dwoma? Jakie są różnice między Maps zwracane przez Collections.synchronizedMap(Map)i ConcurrentHashMaps? Który pasuje do jakiej sytuacji?

Henning
źródło
7
@SmilesinaJar Link jest obecnie zepsuty, oto zarchiwizowana kopia tego artykułu: Dlaczego ConcurrentHashMap jest lepszy niż Hashtable i tak samo dobry jak HashMap
informatik01
2
IBM: How ConcurrentHashMap oferuje wyższą współbieżność bez narażania bezpieczeństwa wątków @ ibm.com/developerworks/java/library/j-jtp08223/...
pramodc84
FYI, Java 6 przyniósł ConcurrentSkipListMapjako kolejną Mapimplementację bezpieczną dla wątków . Zaprojektowany, aby być wysoce współbieżny pod obciążeniem, przy użyciu algorytmu listy pominięć.
Basil Bourque

Odpowiedzi:

423

Do swoich potrzeb użyj ConcurrentHashMap. Umożliwia równoczesną modyfikację mapy z kilku wątków bez konieczności ich blokowania. Collections.synchronizedMap(map)tworzy blokującą mapę, która obniży wydajność, aczkolwiek zapewni spójność (jeśli zostanie właściwie zastosowana).

Użyj drugiej opcji, jeśli chcesz zapewnić spójność danych, a każdy wątek musi mieć aktualny widok mapy. Użyj pierwszej, jeśli wydajność jest krytyczna, a każdy wątek wstawia dane do mapy, a odczyty zdarzają się rzadziej.

Yuval Adam
źródło
8
Patrząc na kod źródłowy, zsynchronizowana mapa jest tylko implementacją z jednym mutexem (blokującym), podczas gdy ConcurrentHashMap jest bardziej skomplikowany w radzeniu sobie z równoczesnym dostępem
Vinze
123
Należy również pamiętać, że ConcurrentHashMap nie zezwala na klucze lub wartości zerowe. NIE są więc równymi alternatywami zsynchronizowanej mapy.
onejigtwojig
24
Myślę, że powinieneś przeczytać to http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/
Mr Spark
5
@AbdullahShaikh Problem podniesiony w tym artykule został naprawiony w Javie 7, a dalsze ulepszenia zostały wprowadzone w Javie 8.
puls0ne
5
@hengxin: jak tylko wykonasz operację składającą się z wielu zapytań lub aktualizacji mapy lub podczas iteracji po mapie, musisz ręcznie zsynchronizować mapę, aby zapewnić spójność. Zsynchronizowane mapy gwarantują spójność tylko dla pojedynczych operacji (wywołań metod) na mapie, co czyni ją często bezwartościową, ponieważ większość rzeczywistych operacji nie jest trywialna, więc i tak musisz ręcznie zsynchronizować.
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   ║ 
╚═══════════════╩═══════════════════════════════════════╩═════════════════════╝

Odnośnie mechanizmu blokującego: Hashtable blokuje obiekt , a ConcurrentHashMapblokuje tylko wiadro .

Sergii Szewczyk
źródło
13
Hashtablenie blokuje części mapy. Spójrz na wdrożenie. Używa synchronizedklucza bez blokady, co w zasadzie oznacza, że ​​blokuje całość hashtablew każdej operacji.
RMachnik,
6
Co z SynchronizedMap?
Samuel Edwin Ward
3
Zachowanie Collections.syncronizedMap jest jak mapy podkładowej, z wyjątkiem Wszystkie metody są bezpieczne wątek
Sergii Shevchyk
5
Wydrukowałbym stół i sprzedałbym za 5 USD za każdy;). Good one @shevchyk
realPK
Edytowane: Żadne z nich nie jest w pełni bezpieczne dla wątków. Jest to nieco mylące dla nowszych programistów. Zobacz: ibm.com/developerworks/java/library/j-jtp07233/index.html, aby zrozumieć, że nawet ConcurrentHashMap nie jest w pełni bezpieczny dla wątków przed zewnętrznymi wyścigami danych. (np .: 1 wątek usuwa wartość, a inny próbuje później sprawdzić, czy jest ona obecna, i umieścić ją, jeśli nie. Jest to warunek wyścigu danych i nadal oznacza, że ​​pomimo użycia „ConcurrentHashMap” nie wszystkie problemy z bezpieczeństwem wątków są złagodzone.
Zombie
142

„Problemy ze skalowalnością” Hashtablewystępują dokładnie w ten sam sposób Collections.synchronizedMap(Map)- używają bardzo prostej synchronizacji, co oznacza, że ​​tylko jeden wątek może uzyskać dostęp do mapy w tym samym czasie.

Nie stanowi to większego problemu, gdy masz proste wstawki i wyszukiwania (chyba że robisz to bardzo intensywnie), ale staje się dużym problemem, gdy musisz iterować całą mapę, co może zająć dużo czasu dla dużej mapy - podczas gdy robi to jeden wątek, wszystkie inne muszą czekać, jeśli chcą coś wstawić lub wyszukać.

Do ConcurrentHashMapużywa bardzo zaawansowanych technik, aby zmniejszyć potrzebę synchronizacji i pozwolić równoległy dostęp czytane przez wielu wątków bez synchronizacji, a co ważniejsze, dostarcza Iteratorże nie wymaga synchronizacji, a nawet pozwala na mapę, aby być modyfikowane podczas interation (choć to sprawia, że nie ma gwarancji, czy nie zostaną zwrócone elementy wstawione podczas iteracji).

Michael Borgwardt
źródło
4
Teraz tego chciałem! :) Niesynchronizowany Iterator to tylko czysta słodycz! Thansk za informacje! :) (:
Kounavi
Świetna odpowiedź ... ale oznacza to, że podczas pobierania wątek nie otrzyma najnowszych aktualizacji, ponieważ wątki czytnika nie są zsynchronizowane.
MrA
@MrA: Czy pytasz o ConcurrentHashMap? A co rozumiesz przez „pobieranie”?
Michael Borgwardt
4
@Michael Borgwardt dla ConcurrentHashmap dla np. Załóżmy, że istnieje wiele wątków. niektóre z nich aktualizują mapę, a niektóre pobierają dane z tej samej mapy. SO w tym scenariuszu, gdy wątki próbują czytać, gwarantuje, że otrzymają najnowsze dane, które zostały zaktualizowane, ponieważ wątki czytnika nie muszą blokować.
MrA
35

ConcurrentHashMap jest preferowany, gdy można go użyć - chociaż wymaga co najmniej Java 5.

Jest przeznaczony do skalowania, gdy jest używany przez wiele wątków. Wydajność może być nieznacznie niższa, gdy tylko jeden wątek uzyskuje dostęp do mapy jednocześnie, ale znacznie lepsza, gdy wiele wątków jednocześnie uzyskuje dostęp do mapy.

Znalazłem wpis na blogu, który odtwarza tabelę z doskonałej książki Java Concurrency In Practice , którą bardzo polecam.

Kolekcje.synchronizedMap mają sens tylko wtedy, gdy trzeba zawinąć mapę z innymi cechami, być może jakąś uporządkowaną mapą, taką jak TreeMap.

Bill Michell
źródło
2
Tak - wydaje mi się, że wspominam tę książkę w każdej innej odpowiedzi, którą udzielam!
Bill Michell
@BillMichell link jest uszkodzony
@Govinda Wyłącz javascript przed uzyskaniem dostępu do linku. Wpis na blogu nadal tam jest!
Bill Michell
32

Główna różnica między tymi dwoma polega na tym, ConcurrentHashMapże zablokuje tylko część danych, które są aktualizowane, podczas gdy inna część danych może być dostępna przez inne wątki. Jednak Collections.synchronizedMap()zablokuje wszystkie dane podczas aktualizacji, inne wątki mogą uzyskać dostęp do danych tylko po zwolnieniu blokady. Jeśli istnieje wiele operacji aktualizacji i stosunkowo niewielka liczba operacji odczytu, należy wybrać ConcurrentHashMap.

Kolejną różnicą jest to, że ConcurrentHashMapnie zachowa kolejności przekazywanych elementów na mapie. Jest to podobne do HashMapprzechowywania danych. Nie ma gwarancji, że kolejność elementów zostanie zachowana. Chociaż Collections.synchronizedMap()zachowa kolejność elementów na mapie, która została przekazana. Na przykład, jeśli przejdziesz TreeMapdo ConcurrentHashMap, kolejność elementów w ConcurrentHashMapmoże nie być taka sama jak kolejność w TreeMap, ale Collections.synchronizedMap()zachowa kolejność.

Ponadto ConcurrentHashMapmoże zagwarantować, że nie zostanie ConcurrentModificationExceptionwyrzucony, gdy jeden wątek aktualizuje mapę, a inny wątek przemierza iterator uzyskany z mapy. Nie Collections.synchronizedMap()można jednak tego zagwarantować.

Jest jeden post, który pokazuje różnice między tymi dwoma, a także ConcurrentSkipListMap.

PixelsTech
źródło
13

Zsynchronizowana mapa:

Mapa zsynchronizowana również nie różni się bardzo od Hashtable i zapewnia podobną wydajność w współbieżnych programach Java. Jedyną różnicą między Hashtable i SynchronizedMap jest to, że SynchronizedMap nie jest dziedzictwem i można owinąć dowolną mapę, aby utworzyć jej zsynchronizowaną wersję za pomocą metody Collections.synchronizedMap ().

ConcurrentHashMap:

Klasa ConcurrentHashMap zapewnia współbieżną wersję standardowego HashMap. Jest to ulepszenie funkcji synchronizedMap dostępnej w klasie Kolekcje.

W przeciwieństwie do Hashtable i zsynchronizowanej mapy, nigdy nie blokuje całej mapy, zamiast tego dzieli mapę na segmenty i blokuje się na nich. Działa lepiej, jeśli liczba wątków czytnika jest większa niż liczba wątków pisarza.

ConcurrentHashMap domyślnie jest podzielony na 16 regionów i stosowane są blokady. Ten domyślny numer można ustawić podczas inicjowania instancji ConcurrentHashMap. Podczas ustawiania danych w określonym segmencie uzyskiwana jest blokada tego segmentu. Oznacza to, że dwie aktualizacje mogą nadal być wykonywane jednocześnie, jeśli wpływają one na osobne segmenty, minimalizując w ten sposób rywalizację o blokadę i maksymalizując wydajność.

ConcurrentHashMap nie zgłasza ConcurrentModificationException

ConcurrentHashMap nie zgłasza ConcurrentModificationException, jeśli jeden wątek próbuje go zmodyfikować, a inny iteruje nad nim

Różnica między synchornizedMap i ConcurrentHashMap

Kolekcje.synchornizedMap (HashMap) zwrócą kolekcję prawie równoważną Hashtable, w której każda operacja modyfikacji na Mapie jest zablokowana na obiekcie Map, natomiast w przypadku ConcurrentHashMap bezpieczeństwo wątków osiąga się poprzez podzielenie całej mapy na inną partycję na podstawie poziomu współbieżności i tylko blokowanie określonej części zamiast blokowania całej mapy.

ConcurrentHashMap nie zezwala na klucze zerowe lub wartości zerowe, podczas gdy zsynchronizowany HashMap zezwala na jeden klucz zerowy.

Podobne linki

Link1

Link2

Porównanie wydajności

Ramesh Papaganti
źródło
12

Jak zwykle występują kompromisy - koszty ogólne - prędkości. Naprawdę musisz wziąć pod uwagę szczegółowe wymagania dotyczące współbieżności aplikacji, aby podjąć decyzję, a następnie przetestować kod, aby sprawdzić, czy jest wystarczająco dobry.

Zach Scrivena
źródło
12

W ConcurrentHashMapblokada jest stosowana do segmentu zamiast całej mapy. Każdy segment zarządza własną wewnętrzną tabelą skrótów. Blokada jest stosowana tylko do operacji aktualizacji. Collections.synchronizedMap(Map)synchronizuje całą mapę.

Satish
źródło
czy możesz spojrzeć na stackoverflow.com/questions/48579060/... ?
gstackoverflow
9

Masz rację HashTable, możesz o tym zapomnieć.

W twoim artykule wspomniano o tym, że chociaż HashTable i zsynchronizowana klasa opakowania zapewniają podstawowe bezpieczeństwo wątków, umożliwiając dostęp do mapy tylko jednemu wątkowi, nie jest to jednak „prawdziwe” bezpieczeństwo wątków, ponieważ wiele operacji złożonych nadal wymaga dodatkowej synchronizacji, ponieważ przykład:

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

Jednak nie sądzę, że ConcurrentHashMapjest to prosta alternatywa dla HashMaptypowego synchronizedbloku, jak pokazano powyżej. Przeczytaj ten artykuł, aby lepiej zrozumieć jego zawiłości.

eljenso
źródło
7

Oto kilka:

1) ConcurrentHashMap blokuje tylko część mapy, ale SynchronizedMap blokuje całą mapę.
2) ConcurrentHashMap ma lepszą wydajność niż SynchronizedMap i jest bardziej skalowalny.
3) W przypadku wielu czytników i jednego pisarza ConcurrentHashMap jest najlepszym wyborem.

Ten tekst pochodzi z różnicy między ConcurrentHashMap i hashtable w Javie

Raj
źródło
7

Możemy osiągnąć bezpieczeństwo wątków za pomocą ConcurrentHashMap oraz synchronizedHashmap i Hashtable. Ale jest duża różnica, jeśli spojrzeć na ich architekturę.

  1. synchronizedHashmap i Hashtable

Oba utrzymają blokadę na poziomie obiektu. Więc jeśli chcesz wykonać dowolną operację, taką jak put / get, musisz najpierw uzyskać blokadę. Jednocześnie inne wątki nie mogą wykonywać żadnych operacji. Tak więc na raz może działać tylko jeden wątek. Tutaj czas oczekiwania wydłuży się. Można powiedzieć, że wydajność jest stosunkowo niska, gdy porównujesz z ConcurrentHashMap.

  1. ConcurrentHashMap

Utrzyma blokadę na poziomie segmentu. Ma 16 segmentów i domyślnie utrzymuje poziom współbieżności na poziomie 16. Tak więc jednocześnie 16 wątków może działać na ConcurrentHashMap. Ponadto operacja odczytu nie wymaga blokady. Tak więc dowolna liczba wątków może wykonać na nim operację get.

Jeśli wątek 1 chce wykonać operację umieszczenia w segmencie 2, a wątek 2 chce wykonać operację umieszczenia w segmencie 4, jest to dozwolone tutaj. Oznacza, że ​​16 wątków może wykonywać operacje aktualizacji (wstawianie / usuwanie) na ConcurrentHashMap na raz.

Aby czas oczekiwania był tutaj krótszy. Dlatego wydajność jest względnie lepsza niż zsynchronizowana mapa skrótów i tabela skrótów.

Sumanth Varada
źródło
1
, 1. co się stanie, jeśli wiele wątków spróbuje edytować ten sam blok? 2. Co się stanie, jeśli powiedzmy, że dwa wątki próbują odczytać dane z tego samego bloku, w którym inny wątek zapisuje dane w tym samym czasie?
prnjn
6

ConcurrentHashMap

  • Powinieneś użyć ConcurrentHashMap, gdy potrzebujesz bardzo wysokiej współbieżności w swoim projekcie.
  • Jest bezpieczny dla wątków bez synchronizacji całej mapy.
  • Odczyty mogą odbywać się bardzo szybko, podczas gdy zapis odbywa się za pomocą blokady.
  • Nie ma blokady na poziomie obiektu.
  • Blokowanie ma znacznie większą szczegółowość na poziomie segmentu mieszania.
  • ConcurrentHashMap nie zgłasza ConcurrentModificationException, jeśli jeden wątek próbuje go zmodyfikować, a inny iteruje nad nim.
  • ConcurrentHashMap używa wielu blokad.

SynchronizedHashMap

  • Synchronizacja na poziomie obiektu.
  • Każda operacja odczytu / zapisu wymaga uzyskania blokady.
  • Zablokowanie całej kolekcji to narzut związany z wydajnością.
  • To zasadniczo daje dostęp tylko do jednego wątku do całej mapy i blokuje wszystkie pozostałe wątki.
  • Może to powodować spór.
  • SynchronizedHashMap zwraca Iterator, który szybko zawiedzie przy równoczesnej modyfikacji.

źródło

Premraj
źródło
4

ConcurrentHashMap jest zoptymalizowany pod kątem równoczesnego dostępu.

Dostęp nie blokuje całej mapy, ale stosuje bardziej szczegółową strategię, która poprawia skalowalność. Istnieją również ulepszenia funkcjonalne specjalnie dla równoczesnego dostępu, np. Współbieżne iteratory.

starblue
źródło
4

Należy zwrócić uwagę na jedną istotną funkcjęConcurrentHashMap inną niż funkcja współbieżności, którą zapewnia, czyli iterator bezpieczny w razie awarii . Widziałem programistów używających ConcurrentHashMaptylko dlatego, że chcą edytować zestaw wpisów - wstaw / usuń podczas iteracji. Collections.synchronizedMap(Map)nie przewiduje fail-safe iterator ale zapewnia fail-fast iterator zamiast. iteratory szybko działające wykorzystują migawkę wielkości mapy, której nie można edytować podczas iteracji.

cześć
źródło
3
  1. Jeśli spójność danych jest bardzo ważna - użyj Hashtable lub Collections.synchronizedMap (mapa).
  2. Jeśli szybkość / wydajność jest bardzo ważna i aktualizacja danych może być zagrożona - użyj ConcurrentHashMap.
Shivam Maharshi
źródło
2

Ogólnie rzecz biorąc, jeśli chcesz skorzystać z funkcji ConcurrentHashMapupewnij się, że jesteś gotowy pominąć „aktualizacje”
(tj. Drukowanie zawartości HashMap nie gwarantuje, że wydrukuje aktualną mapę) i użyj interfejsów API, CyclicBarrieraby zapewnić spójność w programie koło życia.

Kounavi
źródło
1

Metoda Collections.synchronizedMap () synchronizuje wszystkie metody HashMap i skutecznie redukuje ją do struktury danych, do której może wchodzić jeden wątek naraz, ponieważ blokuje każdą metodę na wspólnej blokadzie.

W ConcurrentHashMap synchronizacja odbywa się nieco inaczej. Zamiast blokować każdą metodę na wspólnej blokadzie, ConcurrentHashMap używa osobnej blokady dla oddzielnych segmentów, blokując w ten sposób tylko część mapy. Domyślnie jest 16 wiader, a także osobne zamki dla osobnych wiader. Domyślny poziom współbieżności to 16. To znaczy, że teoretycznie w danym momencie 16 wątków może uzyskać dostęp do ConcurrentHashMap, jeśli wszystkie będą miały osobne segmenty.

infoj
źródło
1

ConcurrentHashMap został zaprezentowany jako alternatywa dla Hashtable w Javie 1.5 jako część pakietu współbieżności. Z ConcurrentHashMap masz lepszy wybór nie tylko, jeśli można go bezpiecznie używać w współbieżnym środowisku wielowątkowym, ale także zapewnia lepszą wydajność niż Hashtable i synchronizedMap. ConcurrentHashMap działa lepiej, ponieważ blokuje część mapy. Pozwala na uzgodnione operacje odczytu, a jednocześnie zachowuje integralność poprzez synchronizację operacji zapisu.

Jak implementowana jest ConcurrentHashMap

ConcurrentHashMap został opracowany jako alternatywa dla Hashtable i obsługuje wszystkie funkcje Hashtable z dodatkowymi możliwościami, tzw. Poziomem współbieżności. ConcurrentHashMap pozwala wielu czytnikom czytać jednocześnie bez użycia bloków. Jest to możliwe dzięki rozdzieleniu mapy na różne części i zablokowaniu tylko części mapy w aktualizacjach. Domyślnie poziom współbieżności wynosi 16, więc mapa jest dzielona na 16 części, a każdą częścią zarządza oddzielny blok. Oznacza to, że 16 wątków może współpracować z Mapą jednocześnie, jeśli działają z różnymi częściami Mapy. To sprawia, że ​​ConcurrentHashMap jest produktywny i nie obniża bezpieczeństwa wątków.

Jeśli interesują Cię niektóre ważne funkcje ConcurrentHashMap i kiedy powinieneś skorzystać z tej realizacji Map - po prostu umieszczam link do dobrego artykułu - Jak korzystać z ConcurrentHashMap w Javie

Oleg Poltoratskii
źródło
0

Oprócz tego, co zostało zasugerowane, chciałbym opublikować kod źródłowy związany z SynchronizedMap.

Aby zapewnić Mapbezpieczeństwo wątku, możemy użyć Collections.synchronizedMapinstrukcji i wprowadzić instancję mapy jako parametr.

Implementacja synchronizedMapw Collectionsjest jak poniżej

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

Jak widać, Mapobiekt wejściowy jest zawijany przez SynchronizedMapobiekt.
Zagłębmy się w implementację 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();}
        }
    }

Co SynchronizedMapmożna streścić jako dodanie pojedynczej blokady do podstawowej metody Mapobiektu wejściowego . Do wszystkich metod chronionych przez zamek nie można uzyskać dostępu przez wiele wątków jednocześnie. Oznacza to normalne operacje, takie jak puti getmogą być wykonywane jednocześnie przez jeden wątek dla wszystkich danych w Mapobiekcie.

Sprawia, że Mapwątek obiektu jest teraz bezpieczny, ale wydajność może stać się problemem w niektórych scenariuszach.

Jest ConcurrentMapto znacznie bardziej skomplikowane w implementacji, więcej szczegółów można znaleźć w Budowaniu lepszej HashMap . W skrócie, został zaimplementowany z uwzględnieniem zarówno bezpieczeństwa wątku, jak i wydajności.

Eugene
źródło