2014-07-02 11 views
6

jestem uznającej Java map jakoCzy rozmiar(), put(), remove(), get() atomic w Java zsynchronizowany HashMap?

Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>()); 

do czynienia z kwestiami współbieżności i synchronizacji na mapie dla wszystkich operacji na nim. Jednak przeczytałem, że synchronizacja nie jest konieczna na synchronizedMap, gdy operacje są atomowe. Sprawdziłem Java API, a dokumentacja HashMap nie wspomina o atomach, więc nie jestem pewna, które z nich są.

mam synchronizacji na następujących połączeń do mapy:

map.size() 

map.put() 

map.remove() 

map.get() 

Ale jeśli niektóre są atomowa wydaje synchronizacja nie jest konieczna dla nich. Które są atomowe?

+3

'HashMap' nie jest kolekcją zsynchronizowaną, więc powinieneś założyć, że żadna operacja nie jest atomowa. – awksp

+1

Wszystkie metody są atomowe, ale wiele wywołań metod nie jest. –

Odpowiedz

10

Zsynchronizowana mapa zgodnie z sugerowaną nazwą jest zsynchronizowana. Każda operacja na niej jest atomowa w stosunku do każdej innej operacji na niej.

Możesz myśleć tak, jakby każda metoda synchronizacji mapy została zadeklarowana za pomocą słowa kluczowego synchronized.

Należy pamiętać, że chociaż poszczególne operacje są atomowej, jeśli je połączyć już nie jesteś atomowej, na przykład:

String value = map.get("key"); 
map.put("key", value+"2"); 

nie jest równoznaczne z zsynchronizowanym niestandardowego kodu:

synchronized (map) { 
    String value = map.get("key"); 
    map.put("key", value+"2"); 
} 

ale raczej:

synchronized (map) { 
    String value = map.get("key"); 
} 
synchronized (map) { 
    map.put("key", value+"2"); 
} 
+0

Chyba różnica między tym a http: // stackoverflow.com/questions/567068/java-synchronized-block-vs-collections-synchronizedmap to to, że w drugim poście druga osoba, która zadała pytanie, chciała zsynchronizować wiele metod. –

+0

Należy również pamiętać, że operacje są poprawnie zsynchronizowane tylko wtedy, gdy KAŻDY dostęp do mapy odbywa się za pomocą zsynchronizowanego opakowania. Jeśli wywołałbyś jakąkolwiek metodę wewnętrznej HashMap (która została przekazana bezpośrednio do 'Collections.synchronizedMap'), nie tylko przestałaby być atomowa, ale mogłaby spowodować niezdefiniowane zachowanie. – Marwin

+0

@Marwin Na szczęście OP nie zapisuje odniesienia do wewnętrznej mapy, ale nawet gdyby chciał, bym argumentował, że użycie go bezpośrednio spowodowałoby niezdefiniowane zachowanie. Byłoby to prawdą tylko wtedy, gdyby dwa współbieżne dostępy do mapy zostały wydane za pośrednictwem wewnętrznej mapy i zsynchronizowanego opakowania. – ciamej

5

HashMap nie jest gwarantowane operacje atomowe. Wywołanie dowolnej metody z różnych wątków (nawet size()) może uszkodzić mapę. Jednak mapa uzyskana przy użyciu Collections.synchronizedMap będzie miała zsynchronizowane każde połączenie (a zatem wątkowo bezpieczne).

Może być jednak potrzebna synchronizacja na wyższym poziomie. Na przykład, jeśli sprawdzisz, czy klucz jest obecny, odczytaj jego rozmiar lub w inny sposób uzyskasz dostęp do danych z mapy, a następnie wykonaj z mapą coś innego, na podstawie wyniku mapa może się zmienić między tymi dwoma połączeniami. W takim przypadku potrzebujesz bloku synchronized, aby wykonać całą transakcję atomową, zamiast zsynchronizowanej mapy (która sprawia, że ​​każde połączenie jest atomowe).

+0

Wykonuję tylko jedno wywołanie funkcji mapy dla wywołania metody, przy czym każde wywołanie funkcji mapy jest niezależne od poprzednich. Więc jestem w dobrej formie, prawda? –

+1

@ La-comadreja - Z tego, co opisujesz, powinieneś być. Wszystko zależy jednak od tego, czy należy traktować sekwencję wywołań metod jako jednostkę. Jeśli tak, to dla tych, które wymagają bloków 'zsynchronizowanych 'zamiast (lub dodatkowo) zsynchronizowanych funkcji map. –

+0

dzięki za rozważną odpowiedź. Każda z metod, w których znajduje się mapa, jest odrębną jednostką, a nie wieloma metodami należącymi do jednostki sekwencyjnej. –

3

Sama mapa jest zsynchronizowana, a nie z niektórymi wewnętrznymi blokadami. Uruchomienie więcej niż jednej operacji na mapie wymaga zsynchronizowanego bloku. W każdym razie, jeśli używasz JDK 1.6 lub nowszego, powinieneś rozważyć optymalne użycie, gdy potrzebujesz zapewnić spójność danych, a każdy twój wątek potrzebuje aktualnego widoku mapy. Jeśli wydajność jest krytyczna, a każdy wątek wstawia tylko dane do mapy, a odczyty występują rzadziej, użyj ścieżki, którą nakreśliłeś. Powiedział, że wydajność może być gorsza, gdy tylko jeden wątek uzyskuje dostęp do ConcurrentHashMap na raz, ale znacznie lepiej, gdy wiele wątków ma dostęp do mapy jednocześnie.