2014-09-23 12 views
14

Tutte le operazioni non retrocompe su una ConcurrentHashMap (put(), remove() ecc.) Devono essere racchiuse in un blocco synchronized(this)? Comprendo che tutte queste operazioni sono sicure per i thread, quindi c'è un reale vantaggio/bisogno nel farlo? Le uniche operazioni utilizzate sono put() e remove().È necessario che una ConcurrentHashMap sia racchiusa in un blocco sincronizzato?

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); 
    } 
    ... 
} 

risposta

35

No, si stanno perdendo i vantaggi di ConcurrentHashMap facendo quello. Si può anche utilizzare un HashMap con synchronized o synchronizedMap() per bloccare l'intera tabella (che è quello che si fa quando avvolgendo le operazioni in synchronized, dal momento che il monitor implicita è l'intera istanza di oggetto.)

Lo scopo di ConcurrentHashMap è quello di aumentare la velocità effettiva del codice concorrente consentendo letture/scritture simultanee sulla tabella senza bloccare l'intera tabella. La tabella supporta questo internamente utilizzando il lock striping (più blocchi invece di uno, con ogni blocco assegnato a un set di bucket hash - vedi Java Concurrency in Practice di Goetz et al).

Una volta che si utilizza ConcurrentHashMap, tutti i metodi mappa standard (put(), remove(), etc.) diventano atomica in virtù del blocco striping ecc nell'implementazione. Gli unici compromessi sono che metodi come size() e isEmpty() potrebbero non restituire risultati accurati, poiché l'unico modo in cui potrebbero essere per tutte le operazioni bloccare l'intera tabella.

L'interfaccia ConcurrentMap interface aggiunge anche nuove operazioni composite atomica come putIfAbsent() (mettere qualcosa solo se la chiave non è già nella mappa), remove() accettando sia chiave e il valore (rimuovere una voce solo se il suo valore è uguale a un parametro che si passa), ecc Queste operazioni usati per richiedere il blocco l'intera tabella perché avevano bisogno due chiamate di metodo per realizzare (ad esempio putIfAbsent() avrebbe bisogno chiamate a entrambi containsKey() e put(), avvolto all'interno di un blocco synchronized, se si stesse utilizzando un Map implementazione standard.) una volta di nuovo, si ottiene un maggiore throughput utilizzando questi metodi, evitando di bloccare l'intera tabella.

6

La sincronizzazione di queste operazioni non ha alcun vantaggio in questo caso: in realtà riduce le prestazioni se non è necessaria la sincronizzazione.

La ragione ConcurrentHashMap è stato creato, è che le mappe sincronizzato (sia attuato a mano come nella domanda e un'istanza nel modo consueto con Collections.synchronizedMap(map)) visualizza cattivo prestazioni quando si accede da tanti fili. Metti e ottieni operazioni stanno bloccando, quindi tutti gli altri thread devono attendere e non possono accedere alla mappa contemporaneamente. Il ConcurrentHashMap - come suggerisce il nome - consente l'accesso simultaneo d'altra parte. Si perde questo vantaggio se si aggiunge la sincronizzazione.