2014-09-23 31 views
14

Czy wszystkie operacje, których nie można wznowić na ConcurrentHashMap (put(), remove() itd.), Należy zawinąć w blok synchronized(this)? Rozumiem, że wszystkie te operacje są bezpieczne dla wątków, więc czy istnieje jakaś realna korzyść/potrzeba? Jedyne używane operacje to put() i remove().Czy plik ConcurrentHashMap musi być zawinięty w zsynchronizowany blok?

protected final Map<String, String> mapDataStore = new ConcurrentHashMap<String, String>(); 

public void updateDataStore(final String key, final String value) { 
    ... 
    synchronized (this) { 
     mapDataStore.put(key, value); 
    } 
    ... 
} 

Odpowiedz

35

Nie, tracą korzyści ConcurrentHashMap robiąc to. można używasz, jak również do HashMap z synchronized lub synchronizedMap() aby zablokować całą tabelę (czyli co zrobić, gdy owijanie operacje w synchronized, ponieważ monitor implikowana jest cała instancja obiektu.)

Celem ConcurrentHashMap jest Zwiększ przepustowość współbieżnego kodu, zezwalając na jednoczesne odczytywanie/zapisywanie na stole bez blokowania całej tabeli. Tablica obsługuje to wewnętrznie za pomocą listwy blokującej (wiele blokad zamiast jednego, z każdą blokadą przypisaną do zestawu haków mieszających - patrz Java Concurrency in Practice autorstwa Goetza i innych).

Gdy używasz ConcurrentHashMap, wszystkie standardowe metody map (put(), remove(), itp.) Stają się atomowe dzięki zastosowaniu paska zamka itp. W implementacji. Jedynymi komplikacjami są to, że metody takie jak size() i isEmpty() niekoniecznie muszą zwracać dokładne wyniki, ponieważ jedynym sposobem, w jaki mogą one być, dla wszystkich operacji jest zablokowanie całej tabeli.

Interfejs ConcurrentMap interface dodaje również nowe operacje złożone atomowy jak putIfAbsent() (umieścić coś tylko wtedy, gdy klucz nie znajduje się już na mapie), remove() przyjmowanie zarówno klucz i wartość (usunąć pozycję tylko wtedy, gdy jego wartość jest równa parametr przejechania) itp. Operacje te wymagały zablokowania całej tabeli, ponieważ wymagały dwóch wywołań metod (np. putIfAbsent() wymagałyby wywołań zarówno containsKey(), jak i put(), zapakowanych wewnątrz jednego bloku synchronized, jeśli używano standardowej implementacji Map). ponownie, zyskujesz większą przepustowość za pomocą tych metod, unikając blokowania całej tabeli.

6

Synchronizacja tych operacji nie przynosi żadnych korzyści - w rzeczywistości obniża wydajność, jeśli nie jest potrzebna synchronizacja.

Powodem utworzenia ConcurrentHashMap jest to, że zsynchronizowane mapy (zaimplementowane ręcznie jak w pytaniu lub utworzone w zwykły sposób z Collections.synchronizedMap(map)) wykazują złą wydajność, gdy dostęp do nich jest uzyskiwany przez wiele wątków. Operacje wstawiania i pobierania są blokowane, więc wszystkie inne wątki muszą czekać i nie mogą jednocześnie uzyskać dostępu do mapy. ConcurrentHashMap - jak sama nazwa wskazuje - umożliwia równoczesny dostęp z drugiej strony. Tracisz tę korzyść, jeśli dodasz synchronizację.