Java ConcurrentHashMap atomica ottenere se presente
-
08-10-2019 - |
Domanda
Come si esegue un get sicuro, se presente operazione su un concorrente Hash Map? (Stessa cosa come putIfAbsent)
Bad esempio, non molto thread-safe (controllo poi agire situazione):
ConcurrentMap<String, SomeObject> concMap = new ...
//... many putIfAbsent and remove operations
public boolean setOption(String id, Object option){
SomeObject obj = concMap.get(id);
if (obj != null){
//what if this key has been removed from the map?
obj.setOption(option);
return true;
}
// in the meantime a putIfAbsent may have been called on the map and then this
//setOption call is no longer correct
return false;
}
Un altro cattivo esempio potrebbe essere:
public boolean setOption(String id, Object option){
if (concMap.contains(id)){
concMap.get(id).setOption(option);
return true;
}
return false;
}
La cosa desiderabile è quello di non collo di bottiglia l'aggiungere, rimuovere e ottenere le operazioni per la sincronizzazione.
Grazie
Soluzione
Cosa in cui sembra essere cercando di fare è quello di bloccare una chiave su più operazioni. Solo ogni operazione è atomica. Questi è un modo semplice per bloccare una chiave, solo per bloccare la carta.
Tuttavia nella "cosa succede se elimino un tasto" caso, tutto quello che puoi fare è di ritardare l'operazione di eliminazione fino a dopo il setOption si chiama. Il risultato dovrebbe essere lo stesso.
È sembrano essere cercando di risolvere un problema che non può avere bisogno di essere risolti. Non hai spiegato perché chiamare setOption dopo che un tasto viene eliminato o mentre la chiave è in attesa di essere eliminato è male.
Altri suggerimenti
Il metodo get()
su un ConcurrentHashMap
è atomico. Dal momento che la mappa non consente valori nulli, attrezzi get()
"get se presente":. Se il risultato è null
, la chiave non era presente
Non utilizzare containsKey
/ get
, basta chiamare get
. Se tale metodo restituisce null
quindi la chiave non era presente altrimenti la chiave era presente, e vi entrato in possesso del valore che è stato mappato al momento della get
.
Dalla documentazione:
Restituisce il valore a cui è associata la chiave specificata, oppure null se questa mappa non contiene la mappatura per la chiave.
Questo è come il tuo secondo esempio dovrebbe essere:
public boolean setOption(String id, Object option) {
SomeObject opt = concMap.get(id);
if (opt == null)
return false;
opt.setOption(option);
return true;
}
Se avete bisogno di fare più operazioni in una singola chiave nel ConcurrentMap, è possibile utilizzare Blocca striping tecnica per ridurre la contesa, ecco un esempio di quadro Guava:
private Striped<Lock> lock;
public boolean setOption(String id, Object option) {
try {
Lock lock = concMap.get(id);
lock.lock();
if (concMap.contains(id)){
concMap.get(id).setOption(option);
return true;
}
return false;
} finally {
lock.unlock();
}
}
In alternativa, dal momento che Java 8: ConcurrentMap.compute è un nuovo metodo atomica, vedere come è fatto su un tasto:
concMap.compute(keyId, (key, value) -> {
dosmth; ... return key; });
P.S. Eventuali variazioni sono con ConcurrentMap.computeIfPresent (), ecc.