È thread-safe. Tuttavia, il modo in cui è thread-safe potrebbe non essere quello che ti aspetti.Ci sono alcuni "suggerimenti" si può vedere da:
Questa classe è completamente interoperabile con Hashtable
in programmi che si basano sulla sua sicurezza thread, ma non sui suoi dettagli di sincronizzazione
Per conoscere tutta la storia in un'immagine più completa, è necessario essere a conoscenza dell'interfaccia ConcurrentMap
.
L'originale Map
fornisce alcuni metodi di lettura/aggiornamento molto semplici. Anche io sono stato in grado di realizzare un'implementazione thread-safe di Map
; ci sono molti casi in cui le persone non possono usare la mia mappa senza considerare il mio meccanismo di sincronizzazione. Questo è un tipico esempio:
if (!threadSafeMap.containsKey(key)) {
threadSafeMap.put(key, value);
}
Questo pezzo di codice non è thread-safe, anche se la mappa stessa è. Due thread che chiamano containsKey()
allo stesso tempo potrebbero pensare che non ci sia una chiave tale che entrambi quindi inseriscano nello Map
.
Per risolvere il problema, è necessario eseguire la sincronizzazione aggiuntiva in modo esplicito. Suppongo che il thread-sicurezza del mio Map si ottiene parole chiave sincronizzati, è necessario fare:
synchronized(threadSafeMap) {
if (!threadSafeMap.containsKey(key)) {
threadSafeMap.put(key, value);
}
}
Tale codice aggiuntivo bisogno di voi per conoscere i "dettagli" di sincronizzazione della mappa. Nell'esempio sopra, abbiamo bisogno di sapere che la sincronizzazione è ottenuta "sincronizzata".
interfaccia ConcurrentMap
fare questo un ulteriore passo avanti. Definisce alcune azioni "complesse" comuni che implicano l'accesso multiplo alla mappa. Ad esempio, l'esempio precedente è esposto come putIfAbsent()
. Con queste azioni "complesse", gli utenti di ConcurrentMap
(nella maggior parte dei casi) non hanno bisogno di sincronizzare le azioni con accesso multiplo alla mappa. Quindi, l'implementazione di Map può eseguire meccanismi di sincronizzazione più complicati per prestazioni migliori. ConcurrentHashhMap
è un buon esempio. La sicurezza del filo viene infatti mantenuta mantenendo blocchi separati per le diverse partizioni della mappa. È thread-safe perché l'accesso simultaneo alla mappa non danneggerà la struttura interna di dati, o causare alcun aggiornamento perso inatteso, ecc
Con tutto questo in mente, il significato di Javadoc sarà più chiaro:
"Le operazioni di recupero (incluso get) generalmente non bloccano" perché ConcurrentHashMap
non sta utilizzando "sincronizzato" per la sicurezza del thread. La logica di get
si prende cura della sicurezza del thread; E se si guarda ulteriormente nel Javadoc:
La tabella è partizionata internamente per cercare di permettere al numero indicato aggiornamenti simultanei senza contesa
Non solo è il recupero non bloccante, anche gli aggiornamenti possono accadere contemporaneamente. Tuttavia, gli aggiornamenti non bloccanti/concomitanti non significa che sia thread-Unsafe. Significa semplicemente che sta usando alcuni modi diversi dal semplice "sincronizzato" per la sicurezza del thread.
Tuttavia, come il meccanismo di sincronizzazione interna non è esposto, se si vuole fare alcune azioni complesse diversi da quelli forniti da ConcurrentMap
, potrebbe essere necessario pensare di cambiare la logica, o prendere in considerazione non utilizzare ConcurrentHashMap
.Per esempio:
// only remove if both key1 and key2 exists
if (map.containsKey(key1) && map.containsKey(key2)) {
map.remove(key1);
map.remove(key2);
}
Se sto leggendo correttamente, vuol dire che il recupero restituirà sempre i risultati dell'ultimo aggiornamento per completare -all'ora in cui è stato avviato il recupero-. Ciò significa che un aggiornamento completo può verificarsi tra il momento in cui un recupero inizia e termina e non cambierà il risultato di tale recupero. – Aurand