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, Hashtable
jest stara implementacja (rozszerzająca przestarzałą Dictionary
klasę), która została później dostosowana do Map
interfejsu. 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 ConcurrentHashMap
s? Który pasuje do jakiej sytuacji?
java
dictionary
concurrency
Henning
źródło
źródło
ConcurrentSkipListMap
jako kolejnąMap
implementację bezpieczną dla wątków . Zaprojektowany, aby być wysoce współbieżny pod obciążeniem, przy użyciu algorytmu listy pominięć.Odpowiedzi:
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.
źródło
Odnośnie mechanizmu blokującego:
Hashtable
blokuje obiekt , aConcurrentHashMap
blokuje tylko wiadro .źródło
Hashtable
nie blokuje części mapy. Spójrz na wdrożenie. Używasynchronized
klucza bez blokady, co w zasadzie oznacza, że blokuje całośćhashtable
w każdej operacji.„Problemy ze skalowalnością”
Hashtable
występują dokładnie w ten sam sposóbCollections.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
ConcurrentHashMap
uż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, dostarczaIterator
ż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).źródło
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.
źródło
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. JednakCollections.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
ConcurrentHashMap
nie zachowa kolejności przekazywanych elementów na mapie. Jest to podobne doHashMap
przechowywania 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 przejdzieszTreeMap
doConcurrentHashMap
, kolejność elementów wConcurrentHashMap
może nie być taka sama jak kolejność wTreeMap
, aleCollections.synchronizedMap()
zachowa kolejność.Ponadto
ConcurrentHashMap
może zagwarantować, że nie zostanieConcurrentModificationException
wyrzucony, gdy jeden wątek aktualizuje mapę, a inny wątek przemierza iterator uzyskany z mapy. NieCollections.synchronizedMap()
można jednak tego zagwarantować.Jest jeden post, który pokazuje różnice między tymi dwoma, a także
ConcurrentSkipListMap
.źródło
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
źródło
Hashtable
iConcurrentHashMap
nie zezwalaj nanull
klucze aninull
wartości.Collections.synchronizedMap(Map)
synchronizuje wszystkie operacje (get
,put
,size
, etc).ConcurrentHashMap
obsługuje pełną współbieżność pobierania danych i regulowaną oczekiwaną współbieżność aktualizacji.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.
źródło
W
ConcurrentHashMap
blokada 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ę.źródło
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:
Jednak nie sądzę, że
ConcurrentHashMap
jest to prosta alternatywa dlaHashMap
typowegosynchronized
bloku, jak pokazano powyżej. Przeczytaj ten artykuł, aby lepiej zrozumieć jego zawiłości.źródło
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
źródło
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ę.
źródło
ConcurrentHashMap
SynchronizedHashMap
źródło
źródło
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.
źródło
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ącychConcurrentHashMap
tylko 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.źródło
źródło
Ogólnie rzecz biorąc, jeśli chcesz skorzystać z funkcji
ConcurrentHashMap
upewnij się, że jesteś gotowy pominąć „aktualizacje”(tj. Drukowanie zawartości HashMap nie gwarantuje, że wydrukuje aktualną mapę) i użyj interfejsów API,
CyclicBarrier
aby zapewnić spójność w programie koło życia.źródło
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.
źródło
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
źródło
Oprócz tego, co zostało zasugerowane, chciałbym opublikować kod źródłowy związany z
SynchronizedMap
.Aby zapewnić
Map
bezpieczeństwo wątku, możemy użyćCollections.synchronizedMap
instrukcji i wprowadzić instancję mapy jako parametr.Implementacja
synchronizedMap
wCollections
jest jak poniżejJak widać,
Map
obiekt wejściowy jest zawijany przezSynchronizedMap
obiekt.Zagłębmy się w implementację
SynchronizedMap
,Co
SynchronizedMap
można streścić jako dodanie pojedynczej blokady do podstawowej metodyMap
obiektu 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 jakput
iget
mogą być wykonywane jednocześnie przez jeden wątek dla wszystkich danych wMap
obiekcie.Sprawia, że
Map
wątek obiektu jest teraz bezpieczny, ale wydajność może stać się problemem w niektórych scenariuszach.Jest
ConcurrentMap
to 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.źródło