Torna alla concorrenza. Ormai è chiaro che per il double checked locking
funzionare la variabile deve essere dichiarata come volatile
. Ma allora cosa succederebbe se il doppio controllo fosse usato come sotto.Bloccaggio con doppia verifica con HashMap normale
class Test<A, B> {
private final Map<A, B> map = new HashMap<>();
public B fetch(A key, Function<A, B> loader) {
B value = map.get(key);
if (value == null) {
synchronized (this) {
value = map.get(key);
if (value == null) {
value = loader.apply(key);
map.put(key, value);
}
}
}
return value;
}
}
Perché in realtà deve essere un ConcurrentHashMap e non un normale HashMap? Tutte le modifiche della mappa vengono eseguite all'interno del blocco synchronized
e il codice non utilizza gli iteratori, quindi tecnicamente non dovrebbero esserci problemi di "modifica simultanea".
Si prega di evitare che suggerisce l'uso di putIfAbsent
/computeIfAbsent
come sto chiedendo circa il concetto di e non l'uso di API :) a meno di utilizzare questa API contribuisce a HashMap
vs ConcurrentHashMap
soggetto.
Aggiornamento 2016-12-30
Questa domanda è stato risposto con un commento qui sotto da Holger "HashMap.get
non modifica la struttura, ma la vostra invocazione del put
fa. Poiché non v'è un'invocazione di get
fuori del blocco sincronizzato, può vedere uno stato incompleto di un'operazione put
che si verifica contemporaneamente. " Grazie!
Poiché la mappa verrà ridimensionata dopo alcuni passaggi, interromperà sicuramente le chiamate sbloccate. –
putIfAbsent/computeIfAbsent sono atomici e non solo per comodità –
Thomas, potresti elaborare "break get calls" per favore. Ho trovato solo riferimenti espliciti a put ed iteratori simultanei nei documenti e durante la ricerca di "accesso simultaneo ad hashmap" –