È sicuro ottenere valori da java.util.HashMap da più thread (nessuna modifica)?


138

C'è un caso in cui una mappa verrà costruita e, una volta inizializzata, non verrà mai più modificata. Tuttavia, sarà possibile accedervi (solo tramite get (chiave)) da più thread. È sicuro usare un java.util.HashMapin questo modo?

(Attualmente sto usando felicemente a java.util.concurrent.ConcurrentHashMap, e non ho misurato la necessità di migliorare le prestazioni, ma sono semplicemente curioso di sapere se un semplice HashMapsarebbe sufficiente. Quindi, questa domanda non è "Quale dovrei usare?", Né è una domanda sulle prestazioni. Piuttosto, la domanda è "Sarebbe sicuro?")


4
Molte risposte qui sono corrette per quanto riguarda l'esclusione reciproca dai thread in esecuzione, ma errate per quanto riguarda gli aggiornamenti di memoria. Ho votato su / giù di conseguenza, ma ci sono ancora molte risposte errate con voti positivi.
Heath Borders,

@Heath Borders, se l'istanza a è stata inizializzata staticamente non modificabile HashMap, dovrebbe essere sicura per la lettura simultanea (poiché altri thread non avrebbero potuto perdere gli aggiornamenti in quanto non c'erano aggiornamenti), giusto?
Kaqqao,

Se viene inizializzato staticamente e non viene mai modificato al di fuori del blocco statico, potrebbe essere ok perché tutte le inizializzazioni statiche sono sincronizzate da ClassLoader. Vale la pena una domanda separata da sola. Lo sincronizzerei ancora esplicitamente e il profilo per verificare che causasse problemi di prestazioni reali.
Heath Borders,

@HeathBorders - cosa intendi con "aggiornamenti di memoria"? La JVM è un modello formale che definisce cose come visibilità, atomicità, relazioni precedenti , ma non usa termini come "aggiornamenti di memoria". Dovresti chiarire, preferibilmente usando la terminologia del JLS.
BeeOnRope,

2
@Dave - Suppongo che non stai ancora cercando una risposta dopo 8 anni, ma per la cronaca, la confusione chiave in quasi tutte le risposte è che si concentrano sulle azioni che esegui sull'oggetto mappa . Hai già spiegato che non modifichi mai l'oggetto, quindi è tutto irrilevante. L'unico potenziale "gotcha" quindi è come pubblichi il riferimento al Map, che non hai spiegato. Se non lo fai in modo sicuro, non è sicuro. Se lo fai in modo sicuro, lo è . Dettagli nella mia risposta.
BeeOnRope,

Risposte:


55

Il tuo linguaggio è sicuro se e solo se il riferimento a HashMapè pubblicato in modo sicuro . Piuttosto che qualsiasi cosa relativa agli interni di HashMapse stessa, la pubblicazione sicura si occupa di come il thread di costruzione rende visibile il riferimento alla mappa ad altri thread.

Fondamentalmente, l'unica razza possibile qui è tra la costruzione del HashMape tutti i thread di lettura che possono accedervi prima che sia completamente costruito. Gran parte della discussione riguarda ciò che accade allo stato dell'oggetto mappa, ma questo è irrilevante poiché non lo si modifica mai, quindi l'unica parte interessante è come HashMapviene pubblicato il riferimento.

Ad esempio, immagina di pubblicare la mappa in questo modo:

class SomeClass {
   public static HashMap<Object, Object> MAP;

   public synchronized static setMap(HashMap<Object, Object> m) {
     MAP = m;
   }
}

... e ad un certo punto setMap()viene chiamato con una mappa, e altri thread stanno usando SomeClass.MAPper accedere alla mappa e verificare la presenza di null in questo modo:

HashMap<Object,Object> map = SomeClass.MAP;
if (map != null) {
  .. use the map
} else {
  .. some default behavior
}

Questo non è sicuro anche se probabilmente appare come se lo fosse. Il problema è che non c'è è accade-prima relazione tra l'insieme di SomeObject.MAPe la successiva lettura su un altro filo, in modo che il filo di lettura è libero di visualizzare una mappa parzialmente costruito. Questo può praticamente fare qualsiasi cosa e anche in pratica fa cose come mettere il thread di lettura in un ciclo infinito .

Per pubblicare in modo sicuro la mappa, è necessario stabilire un accade-prima di relazione tra la scrittura del riferimento al HashMap(vale a dire, la pubblicazione ) e le successive lettori di quella di riferimento (ad esempio, il consumo). Per comodità, ci sono solo un paio di facile da ricordare i modi per realizzare che [1] :

  1. Scambiare il riferimento attraverso un campo correttamente bloccato ( JLS 17.4.5 )
  2. Utilizzare l'inizializzatore statico per eseguire gli archivi di inizializzazione ( JLS 12.4 )
  3. Scambiare il riferimento tramite un campo volatile ( JLS 17.4.5 ), o come conseguenza di questa regola, tramite le classi AtomicX
  4. Inizializza il valore in un campo finale ( JLS 17.5 ).

Quelli più interessanti per il tuo scenario sono (2), (3) e (4). In particolare, (3) si applica direttamente al codice che ho sopra: se trasformi la dichiarazione di MAP:

public static volatile HashMap<Object, Object> MAP;

allora tutto è kosher: lettori che vedono non nullo valore hanno necessariamente accade-prima relazione con il negozio per MAPe quindi vedere tutti i punti vendita associati con la mappa di inizializzazione.

Gli altri metodi cambiano la semantica del tuo metodo, poiché sia ​​(2) (usando l'inizializzatore statico) che (4) (usando final ) implicano che non puoi impostare MAPdinamicamente in fase di esecuzione. Se non è necessario farlo, dichiarare semplicemente MAPcome static final HashMap<>e si garantisce una pubblicazione sicura.

In pratica, le regole sono semplici per un accesso sicuro a "oggetti mai modificati":

Se stai pubblicando un oggetto che non è intrinsecamente immutabile (come in tutti i campi dichiarati final) e:

  • È già possibile creare l'oggetto che verrà assegnato al momento della dichiarazione a : basta usare un finalcampo (incluso static finalper i membri statici).
  • Si desidera assegnare l'oggetto in un secondo momento, dopo che il riferimento è già visibile: utilizzare un campo volatile b .

Questo è tutto!

In pratica, è molto efficiente. L'uso di un static finalcampo, ad esempio, consente alla JVM di assumere il valore invariato per la durata del programma e di ottimizzarlo pesantemente. L'uso di un finalcampo membro consente alla maggior parte delle architetture di leggere il campo in modo equivalente a un normale campo letto e non inibisce ulteriori ottimizzazioni c .

Infine, l'uso di volatileha un certo impatto: nessuna barriera hardware è necessaria su molte architetture (come x86, in particolare quelle che non consentono alle letture di passare le letture), ma al momento della compilazione potrebbero non esserci alcune ottimizzazioni e riordini - ma questo l'effetto è generalmente piccolo. In cambio, in realtà ottieni di più di quello che hai richiesto - non solo puoi pubblicarne uno in sicurezza HashMap, puoi anche archiviare quanti più HashMaps non modificati vuoi allo stesso riferimento ed essere sicuro che tutti i lettori vedranno una mappa pubblicata in modo sicuro .

Per ulteriori dettagli cruenti, consultare Shipilev o questa FAQ di Manson e Goetz .


[1] Quotazione diretta da Shipilev .


a Sembra complicato, ma intendo dire che è possibile assegnare il riferimento in fase di costruzione, nel punto di dichiarazione o nel costruttore (campi membri) o inizializzatore statico (campi statici).

b Facoltativamente, è possibile utilizzare un synchronizedmetodo per ottenere / impostare o un AtomicReferenceo qualcosa del genere, ma stiamo parlando del lavoro minimo che è possibile eseguire.

c Alcune architetture con modelli di memoria molto deboli (Sto guardando voi , Alpha) possono richiedono un certo tipo di barriera di lettura prima di una finallettura - ma questi sono molto rare oggi.


never modify HashMapnon significa che state of the map objectsia sicuro per il thread, credo. Dio conosce l'implementazione della biblioteca, se il documento ufficiale non dice che è sicuro per i thread.
Jiang YD,

@JiangYD - hai ragione, in alcuni casi c'è un'area grigia lì: quando diciamo "modifica" ciò che realmente intendiamo è un'azione che esegue internamente alcune scritture che potrebbero correre con letture o scritture su altri thread. Queste scritture potrebbero essere dettagli di implementazione interna, quindi anche un'operazione che sembra "sola lettura" come get()potrebbe effettivamente eseguire alcune scritture, ad esempio aggiornando alcune statistiche (o nel caso di un ordine di accesso che LinkedHashMapaggiorna l'ordine di accesso). Quindi una lezione ben scritta dovrebbe fornire una documentazione che lo chiarisca se ...
BeeOnRope,

... apparentemente le operazioni di "sola lettura" sono realmente di sola lettura internamente nel senso della sicurezza dei thread. Nella libreria standard C ++, ad esempio, esiste una regola generale secondo cui le funzioni dei membri contrassegnate constsono veramente di sola lettura in tal senso (internamente, possono comunque eseguire scritture, ma dovranno essere rese thread-safe). Non esiste una constparola chiave in Java e non sono a conoscenza di alcuna garanzia coperta documentata, ma in generale le classi di libreria standard si comportano come previsto e le eccezioni sono documentate (vedere l' LinkedHashMapesempio in cui le operazioni di RO come quelle getsono esplicitamente menzionate come non sicure).
BeeOnRope,

@JiangYD - infine, tornando alla tua domanda originale, poiché nella documentazioneHashMap abbiamo effettivamente il comportamento di sicurezza dei thread per questa classe: se più thread accedono contemporaneamente a una mappa hash e almeno uno dei thread modifica strutturalmente la mappa, deve essere sincronizzato esternamente. (Una modifica strutturale è qualsiasi operazione che aggiunge o elimina una o più mappature; la semplice modifica del valore associato a una chiave che un'istanza contiene già non è una modifica strutturale.)
BeeOnRope

Quindi, per i HashMapmetodi che prevediamo di essere di sola lettura, sono di sola lettura, in quanto non modificano strutturalmente il file HashMap. Naturalmente, questa garanzia potrebbe non valere per altre Mapimplementazioni arbitrarie , ma la domanda riguarda in HashMapparticolare.
BeeOnRope,

70

Jeremy Manson, il dio quando si tratta del modello di memoria Java, ha un blog in tre parti su questo argomento - perché in sostanza stai ponendo la domanda "È sicuro accedere a un HashMap immutabile" - la risposta è sì. Ma devi rispondere al predicato a quella domanda che è: "È la mia HashMap immutabile". La risposta potrebbe sorprenderti: Java ha un insieme di regole relativamente complicate per determinare l'immutabilità.

Per maggiori informazioni sull'argomento, leggi i post sul blog di Jeremy:

Parte 1 sull'immutabilità in Java: http://jeremymanson.blogspot.com/2008/04/immutability-in-java.html

Parte 2 sull'immutabilità in Java: http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-2.html

Parte 3 sull'immutabilità in Java: http://jeremymanson.blogspot.com/2008/07/immutability-in-java-part-3.html


3
È un buon punto, ma mi affido all'inizializzazione statica, durante la quale non sfuggono riferimenti, quindi dovrebbe essere sicuro.
Dave L.,

5
Non riesco a vedere come questa sia una risposta molto apprezzata (o anche una risposta). Per uno, non risponde nemmeno alla domanda e non menziona l'unico principio chiave che deciderà se è sicuro o meno: pubblicazione sicura . La "risposta" si riduce a "è complicato" e qui ci sono tre (complessi) collegamenti che puoi leggere.
BeeOnRope,

Risponde alla domanda alla fine della prima frase. In termini di risposta, sta sollevando il punto che l'immutabilità (citata nel primo paragrafo della domanda) non è semplice, insieme a risorse preziose che spiegano ulteriormente questo argomento. I punti non misurano se si tratti di una risposta, ma misurano se la risposta è stata "utile" per gli altri. La risposta accettata significa che era la risposta che l'OP stava cercando, che la tua risposta ha ricevuto.
Jesse,

@Jesse non sta rispondendo alla domanda alla fine della prima frase, sta rispondendo alla domanda "è sicuro accedere a un oggetto immutabile", che può o meno applicarsi alla domanda del PO come sottolinea la frase successiva. Fondamentalmente questa è una risposta di tipo "vai a capire tu stesso" quasi solo un link, che non è una buona risposta per SO. Per quanto riguarda i voti positivi, penso che sia più una funzione dell'età di 10,5 anni e un argomento frequentemente cercato. Ha ricevuto solo pochi voti netti negli ultimi anni, quindi forse la gente sta arrivando :).
BeeOnRope,

35

Le letture sono sicure dal punto di vista della sincronizzazione ma non dal punto di vista della memoria. Questo è qualcosa che è ampiamente frainteso dagli sviluppatori Java, anche qui su StackOverflow. (Osservare la valutazione di questa risposta per la prova.)

Se sono in esecuzione altri thread, è possibile che non venga visualizzata una copia aggiornata di HashMap se non è presente memoria che scrive dal thread corrente. Le scritture di memoria avvengono mediante l'uso di parole chiave sincronizzate o volatili o mediante l'uso di alcuni costrutti di concorrenza java.

Vedi l'articolo di Brian Goetz sul nuovo modello di memoria Java per i dettagli.


Ci scusiamo per il doppio invio Heath, ho notato il tuo solo dopo aver inviato il mio. :)
Alexander,

2
Sono contento che ci siano altre persone qui che capiscono davvero gli effetti della memoria.
Heath Borders,

1
In effetti, anche se nessun thread vedrà l'oggetto prima che sia inizializzato correttamente, quindi non penso che sia un problema in questo caso.
Dave L.,

1
Dipende interamente da come viene inizializzato l'oggetto.
Bill Michell,

1
La domanda dice che una volta inizializzata la HashMap, non ha intenzione di aggiornarla ulteriormente. Da allora in poi, vuole solo usarlo come una struttura di dati di sola lettura. Penso che sarebbe sicuro farlo, a condizione che i dati memorizzati nella sua Mappa siano immutabili.
Binita Bharati,

9

Dopo un po 'più di ricerca, ho trovato questo nel documento java (enfasi mio):

Si noti che questa implementazione non è sincronizzata. Se più thread accedono contemporaneamente a una mappa hash e almeno uno dei thread modifica la mappa strutturalmente, deve essere sincronizzata esternamente. (Una modifica strutturale è qualsiasi operazione che aggiunge o elimina una o più mappature; la semplice modifica del valore associato a una chiave che un'istanza contiene già non è una modifica strutturale.)

Ciò sembra implicare che sarà sicuro, supponendo che sia vero il contrario dell'affermazione.


1
Mentre questo è un consiglio eccellente, come affermano altre risposte, c'è una risposta più sfumata nel caso di un'istanza di mappa immutabile, pubblicata in modo sicuro. Ma dovresti farlo solo se sai cosa stai facendo.
Alex Miller,

1
Speriamo che con domande come queste, più di noi sappiano cosa stiamo facendo.
Dave L.,

Questo non è proprio corretto. Come affermano le altre risposte, tra l'ultima modifica e tutte le successive letture "thread-safe" deve esserci un evento precedente . Normalmente questo significa che è necessario pubblicare in modo sicuro l'oggetto dopo che è stato creato e le sue modifiche sono state apportate. Vedi la prima risposta contrassegnata corretta.
Markspace

9

Una nota è che in alcune circostanze, un get () da una HashMap non sincronizzata può causare un ciclo infinito. Questo può accadere se un put () simultaneo provoca una nuova versione della mappa.

http://lightbody.net/blog/2005/07/hashmapget_can_cause_an_infini.html


1
In realtà ho visto questo blocco della JVM senza consumare CPU (che è forse peggio)
Peter Lawrey

2
Penso che questo codice sia stato riscritto in modo tale che non sia più possibile ottenere il ciclo infinito. Ma non dovresti continuare a ricevere e mettere da una HashMap non sincronizzata per altri motivi.
Alex Miller,

@AlexMiller anche a parte gli altri motivi (presumo si stia riferendo alla pubblicazione sicura), non penso che una modifica dell'implementazione dovrebbe essere un motivo per allentare le restrizioni di accesso, a meno che non sia esplicitamente consentito dalla documentazione. Come succede, HashMap Javadoc per Java 8 contiene ancora questo avviso:Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally.
shmosel

8

C'è una svolta importante però. L'accesso alla mappa è sicuro, ma in generale non è garantito che tutti i thread vedranno esattamente lo stesso stato (e quindi i valori) di HashMap. Ciò può accadere su sistemi multiprocessore in cui le modifiche a HashMap eseguite da un thread (ad esempio, quello che l'ha popolato) possono trovarsi nella cache di quella CPU e non saranno visibili dai thread in esecuzione su altre CPU, fino a quando un'operazione di recinzione di memoria non è eseguito garantendo la coerenza della cache. La specifica del linguaggio Java è esplicita su questo: la soluzione è acquisire un blocco (sincronizzato (...)) che emette un'operazione di memoria. Quindi, se sei sicuro che dopo aver popolato HashMap ciascuno dei thread acquisisce QUALSIASI blocco, da quel momento in poi è OK accedere a HashMap da qualsiasi thread fino a quando HashMap non viene nuovamente modificato.


Non sono sicuro che l'accesso al thread acquisirà alcun blocco, ma sono sicuro che non avranno un riferimento all'oggetto fino a quando non è stato inizializzato, quindi non credo che possano avere una copia obsoleta.
Dave L.,

@Alex: il riferimento a HashMap può essere volatile per creare le stesse garanzie di visibilità della memoria. @Dave: è possibile vedere i riferimenti a nuovi objs prima che il lavoro del suo ctor diventi visibile sul tuo thread.
Chris Vest,

@Christian Nel caso generale, certamente. Stavo dicendo che in questo codice non lo è.
Dave L.,

L'acquisizione di un blocco RANDOM non garantisce la cancellazione dell'intera cache della CPU del thread. Dipende dall'implementazione di JVM e molto probabilmente non viene fatto in questo modo.
Pierre,

Sono d'accordo con Pierre, non credo che acquisire un blocco sarà sufficiente. Devi sincronizzare sullo stesso blocco per rendere visibili le modifiche.
damluar,

5

Secondo http://www.ibm.com/developerworks/java/library/j-jtp03304/ # Sicurezza di inizializzazione è possibile rendere HashMap un campo finale e al termine del costruttore verrà pubblicato in modo sicuro.

... Sotto il nuovo modello di memoria, c'è qualcosa di simile a una relazione che precede tra la scrittura di un campo finale in un costruttore e il carico iniziale di un riferimento condiviso a quell'oggetto in un altro thread. ...


Questa risposta è di bassa qualità, è la stessa della risposta di @taylor gauthier ma con meno dettagli.
Snicolas,

1
Ummmm ... non essere un asino, ma ce l'hai all'indietro. Taylor ha detto "no, guarda questo post del blog, la risposta potrebbe sorprenderti", mentre in realtà questa risposta aggiunge qualcosa di nuovo che non sapevo ... A proposito di una relazione che accade prima della scrittura di un campo finale in un costruttore. Questa risposta è eccellente e sono contento di averlo letto.
Ajax

Eh? Questa è l' unica risposta corretta che ho trovato dopo aver fatto scorrere le risposte più votate. La chiave è pubblicata in modo sicuro e questa è l'unica risposta che la menziona persino.
BeeOnRope,

3

Quindi lo scenario che hai descritto è che devi mettere un sacco di dati in una mappa, quindi quando hai finito di popolarlo lo consideri immutabile. Un approccio "sicuro" (nel senso che stai imponendo che sia veramente trattato come immutabile) è quello di sostituire il riferimento con Collections.unmodifiableMap(originalMap)quando sei pronto a renderlo immutabile.

Per un esempio di come le mappe possono fallire se utilizzate contemporaneamente e la soluzione suggerita che ho citato, dai un'occhiata a questa parata di bug: bug_id = 6423457


2
Questo è "sicuro" in quanto rafforza l'immutabilità, ma non affronta il problema di sicurezza del thread. Se l'accesso alla mappa è sicuro con il wrapper UnmodifiableMap, è sicuro senza di essa e viceversa.
Dave L.,

2

Questa domanda è stata affrontata nel libro "Concorrenza nella pratica" di Brian Goetz (Listato 16.8, pagina 350):

@ThreadSafe
public class SafeStates {
    private final Map<String, String> states;

    public SafeStates() {
        states = new HashMap<String, String>();
        states.put("alaska", "AK");
        states.put("alabama", "AL");
        ...
        states.put("wyoming", "WY");
    }

    public String getAbbreviation(String s) {
        return states.get(s);
    }
}

Poiché statesviene dichiarato come finale la sua inizializzazione viene eseguita all'interno del costruttore della classe del proprietario, qualsiasi thread che in seguito legge questa mappa è sicuro di vederla al momento in cui termina il costruttore, a condizione che nessun altro thread tenterà di modificare il contenuto della mappa.


1

Tieni presente che anche nel codice a thread singolo, la sostituzione di una ConcurrentHashMap con una HashMap potrebbe non essere sicura. ConcurrentHashMap proibisce null come chiave o valore. HashMap non li proibisce (non chiedere).

Pertanto, nella situazione improbabile che il codice esistente possa aggiungere un valore nullo alla raccolta durante l'installazione (presumibilmente in un caso di errore di qualche tipo), la sostituzione della raccolta come descritto cambierà il comportamento funzionale.

Detto questo, purché tu non faccia nient'altro che letture simultanee da una HashMap siano sicure.

[Modifica: per "letture simultanee", intendo che non ci sono anche modifiche simultanee.

Altre risposte spiegano come garantire ciò. Un modo è rendere la mappa immutabile, ma non è necessaria. Ad esempio, il modello di memoria JSR133 definisce esplicitamente l'avvio di un thread come un'azione sincronizzata, il che significa che le modifiche apportate nel thread A prima che inizi il thread B sono visibili nel thread B.

Il mio intento non è quello di contraddire quelle risposte più dettagliate sul modello di memoria Java. Questa risposta ha lo scopo di sottolineare che anche a parte i problemi di concorrenza, esiste almeno una differenza API tra ConcurrentHashMap e HashMap, che potrebbe far sparire anche un programma a thread singolo che ha sostituito l'uno con l'altro.]


Grazie per l'avvertimento, ma non ci sono tentativi di utilizzare chiavi o valori null.
Dave L.,

Pensavo che non ci sarebbe stato. i null nelle raccolte sono un angolo folle di Java.
Steve Jessop,

Non sono d'accordo con questa risposta. "Le letture simultanee da una HashMap sono sicure" di per sé non è corretto. Non indica se le letture avvengono su una mappa mutabile o immutabile. Per essere corretti, dovresti leggere "Letture simultanee da un'HashMap immutabile sono sicure"
Taylor Gautier,

2
Non secondo gli articoli a cui sei collegato: il requisito è che la mappa non deve essere modificata (e le modifiche precedenti devono essere visibili a tutti i thread del lettore), non che sia immutabile (che è un termine tecnico in Java ed è un condizioni sufficienti ma non necessarie per la sicurezza).
Steve Jessop,

Anche una nota ... l'inizializzazione di una classe si sincronizza implicitamente sullo stesso blocco (sì, è possibile eseguire il deadlock negli inizializzatori di campi statici), quindi se l'inizializzazione avviene staticamente, sarebbe impossibile per chiunque vederla prima che l'inizializzazione sia completa, come dovrebbero essere bloccati nel metodo ClassLoader.loadClass sullo stesso blocco acquisito ... E se ti stai chiedendo di caricatori di classi diversi con copie diverse dello stesso campo, avresti ragione ... ma sarebbe ortogonale al nozione di condizioni di gara; i campi statici di un classloader condividono un recinto di memoria.
Ajax,

0

http://www.docjar.com/html/api/java/util/HashMap.java.html

ecco la fonte per HashMap. Come puoi dire, non c'è assolutamente nessun codice di blocco / mutex lì.

Ciò significa che mentre va bene leggere da una HashMap in una situazione multithread, utilizzerei sicuramente una ConcurrentHashMap se ci fossero più scritture.

La cosa interessante è che sia .NET HashTable sia Dictionary <K, V> hanno un codice di sincronizzazione integrato.


2
Penso che ci siano classi in cui la semplice lettura simultanea può metterti nei guai, ad esempio a causa dell'uso interno di variabili di istanza temporanee. Quindi è probabilmente necessario esaminare attentamente l'origine, più che una scansione rapida per il codice di blocco / mutex.
Dave L.,

0

Se l'inizializzazione e ogni put sono sincronizzati, si viene salvati.

Il seguente codice viene salvato perché il classloader si occuperà della sincronizzazione:

public static final HashMap<String, String> map = new HashMap<>();
static {
  map.put("A","A");

}

Il seguente codice viene salvato perché la scrittura di volatile si occuperà della sincronizzazione.

class Foo {
  volatile HashMap<String, String> map;
  public void init() {
    final HashMap<String, String> tmp = new HashMap<>();
    tmp.put("A","A");
    // writing to volatile has to be after the modification of the map
    this.map = tmp;
  }
}

Questo funzionerà anche se la variabile membro è final perché anche final è volatile. E se il metodo è un costruttore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.