Perché ConcurrentHashMap evitare che i tasti e valori nulli?
-
22-08-2019 - |
Domanda
Il JavaDoc di ConcurrentHashMap dice questo:
Come
Hashtable
ma a differenza diHashMap
, questa classe non permettononull
da utilizzare come valore chiave o.
La mia domanda: perché
2 ° domanda: perché non permettere tabella hash nulla
Ho usato un sacco di HashMaps per la memorizzazione dei dati. Ma quando si passa a ConcurrentHashMap ho avuto più volte nei guai a causa di NullPointerExceptions.
Soluzione
Dall'autore di ConcurrentHashMap
se stesso (Doug Lea) :
Il motivo principale che i valori nulli non sono ammessi in ConcurrentMaps (ConcurrentHashMaps, ConcurrentSkipListMaps) è che le ambiguità che può essere solo a malapena tollerabile nelle mappe non concorrenti non può essere sistemati. Il principale è che, se i rendimenti
map.get(key)
null
, è Non in grado di rilevare se il tasto mappe esplicitamentenull
vs la chiave non è mappato. In una mappa non simultanea, è possibile controllare questa viamap.contains(key)
, ma in un unico concorrente, la mappa potrebbe essere cambiata tra le chiamate.
Altri suggerimenti
Credo che sia, almeno in parte, per consentire di combinare containsKey
e get
in una singola chiamata. Se la mappa può contenere valori nulli, non c'è modo di dire se get
sta tornando un nulla perché non c'era nessuna chiave per quel valore, o semplicemente perché il valore è nullo.
Perché è un problema? Perché non esiste un modo sicuro per farlo da soli. Prendere il seguente codice:
if (m.containsKey(k)) {
return m.get(k);
} else {
throw new KeyNotPresentException();
}
Poiché m
è una mappa concorrente, chiave k può essere eliminato tra le chiamate containsKey
e get
, causando questo frammento di restituire un nulla che non era mai nella tabella, piuttosto che il KeyNotPresentException
desiderato.
Normalmente si dovrebbe risolvere il sincronizzando, ma con una mappa concomitante che, naturalmente, non funzionerà. Da qui la firma per get
doveva cambiare, e l'unico modo per farlo in modo compatibile all'indietro era di impedire all'utente di inserire valori nulli, in primo luogo, e continuare ad utilizzare che come segnaposto per "chiave non trovata".
Josh Bloch progettato HashMap
; Doug Lea progettato ConcurrentHashMap
. Spero che non sia diffamatorio. In realtà penso che il problema è che i null richiedono spesso involucro in modo che il vero nulla può stare non inizializzata. Se il codice cliente richiede i null allora può pagare il (certamente piccola) costo di confezionamento nulli per sé.
ConcurrentHashMap è thread-safe. Credo che non permettendo chiavi e valori nulli era una parte di fare in modo che sia thread-safe.
Credo che il seguente frammento di documentazione delle API dà un buon suggerimento: "Questa classe è completamente interoperabile con Hashtable in programmi basati sulla sua sicurezza filo ma non delle sue modalità di sincronizzazione."
Probabilmente Volevano solo fare ConcurrentHashMap
pienamente compatibile / intercambiabili a Hashtable
. E come Hashtable
non consente chiavi e valori nulli ..
Non è possibile sincronizzare su un nullo.
Edit: Questo non è esattamente il motivo per cui in questo caso. Inizialmente ho pensato che ci fosse qualcosa di fantasia in corso con bloccaggio cose contro aggiornamenti simultanei o altrimenti utilizzando il monitor oggetto di rilevare se qualcosa è stato modificato, ma dopo aver esaminato il codice sorgente sembra mi sbagliavo - non si bloccano con un 'segmento' sulla base di una maschera di bit di l'hash.
In questo caso, ho il sospetto che lo hanno fatto per copiare Hashtable, e ho il sospetto Hashtable fatto perché nel mondo dei database relazionali, null! = Null, in modo da utilizzare un null come chiave non ha alcun significato.
Non credo che negare il riconoscimento di valore nullo è una corretta opzione. In molti casi, noi vogliamo fare inserire una chiave con valore nullo nella mappa con-corrente. Tuttavia, utilizzando ConcurrentHashMap, non possiamo farlo. Suggerisco che la venuta versione del JDK in grado di supportare questo.