2014-07-02 9 views
6

sto dichiarando una mappa Java comeAre size(), put(), remove(), get() atomico in Java HashMap sincronizzato?

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

per affrontare i problemi di concorrenza, e la sincronizzazione sulla mappa per tutte le operazioni su di esso. Tuttavia, ho letto che la sincronizzazione non è necessaria su un synchronizedMap quando le operazioni sono atomiche. Ho controllato l'API Java e la documentazione di HashMap non sembra menzionare quale sia atomica, quindi non sono sicuro di quale sia.

che sto sincronizzazione sui seguenti chiamate alla mappa:

map.size() 

map.put() 

map.remove() 

map.get() 

Ma se alcuni sono atomica, sembra sincronizzazione non è necessaria per questi. Quali sono atomici?

+3

'HashMap' non è una raccolta sincronizzata, quindi è necessario assumere che nessuna operazione sia atomica. – awksp

+1

Tutti i metodi sono atomici, ma non più le chiamate ai metodi. –

risposta

10

Una mappa sincronizzata come suggerisce il nome è sincronizzata. Ogni operazione su di essa è atomica rispetto a qualsiasi altra operazione su di essa.

Si può pensare ad esso come se ogni metodo della propria mappa sincronizzata fosse dichiarato con una parola chiave synchronized.

prega di tenere presente che, anche se le singole operazioni sono atomiche, se si combinano non sono più atomica, per esempio:

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

non è equivalente al codice sincronizzato personalizzato:

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

ma piuttosto:

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

Immagino la differenza tra questo e http: // StackOverflow.it/questions/567068/java-synchronized-block-vs-collections-synchronizedmap è che nell'altro post, l'altra persona che ha posto la domanda voleva sincronizzare più metodi. –

+0

Si noti inoltre che le operazioni sono correttamente sincronizzate solo quando QUALSIASI accesso alla mappa viene effettuato tramite il wrapper sincronizzato. Se chiamassi direttamente un metodo della HashMap interna (quella passata a 'Collections.synchronizedMap'), non solo avrebbe cessato di essere atomico, ma avrebbe potuto comportare un comportamento indefinito. – Marwin

+0

@ Marwin Fortunatamente l'OP non sta salvando un riferimento alla mappa interna, anche se anche se lo farei direi che l'utilizzo diretto comporterebbe un comportamento indefinito. Ciò sarebbe vero solo se due accessi simultanei alla mappa sono stati emessi attraverso la mappa interna e il wrapper sincronizzato. – ciamej

5

Un HashMap non è garantito per avere operazioni atomiche. La chiamata a uno dei suoi metodi da thread diversi (anche size()) può danneggiare la mappa. Tuttavia, una mappa ottenuta utilizzando Collections.synchronizedMap avrà ciascuna chiamata sincronizzata (e quindi thread-safe).

Tuttavia, potrebbe essere necessaria la sincronizzazione di livello superiore. Ad esempio, se si verifica se è presente una chiave, si legge la dimensione o si accede in altro modo alla mappa e quindi si fa qualcos'altro con la mappa in base al risultato, la mappa potrebbe essere cambiata tra le due chiamate. In tal caso, è necessario un blocco synchronized per rendere l'intera transazione atomica, piuttosto che una mappa sincronizzata (che rende semplicemente ogni chiamata atomica).

+0

Sto solo effettuando una chiamata a una funzione mappa per chiamata di metodo, con ogni chiamata di funzione di mappa indipendente da quelle precedenti. Quindi sono in chiaro, giusto? –

+1

@ La-comadreja: da ciò che descrivi, dovresti esserlo. Ma tutto dipende dal fatto che sia necessario trattare una sequenza di invocazioni di metodi come un'unità. Se è così, allora per quelli hai bisogno di usare blocchi 'sincronizzati' invece di (o in aggiunta a) funzioni di mappa sincronizzate. –

+0

grazie per la tua risposta riflessiva. Ciascuno dei metodi in cui si trova la Mappa è un'unità distinta, piuttosto che più metodi appartenenti a un'unità sequenziale. –

3

La mappa stessa è sincronizzata, non alcuni blocchi interni. L'esecuzione di più di un'operazione sulla mappa richiede un blocco sincronizzato. In ogni caso, se si utilizza un JDK 1.6 o superiore, si dovrebbe considerare l'utilizzo di ConcurrentHashMap

ConcurrentHashMap è ottimale quando è necessario garantire la coerenza dei dati e ciascuno dei thread richiede una vista corrente della mappa. Se le prestazioni sono critiche e ogni thread inserisce solo dati nella mappa, con letture che si verificano meno frequentemente, quindi utilizzare il percorso che hai delineato. Detto questo, le prestazioni potrebbero essere più scarse solo quando un singolo thread accede a ConcurrentHashMap alla volta, ma in modo significativo quando più thread accedono contemporaneamente alla mappa.