Domanda

Quando utilizzo una qualsiasi delle classi Java.util.ConCurrent, devo ancora sincronizzare l'accesso sull'istanza per evitare problemi di visibilità tra thread di differenza?

Elaborando un po 'di più la domanda

Quando si utilizza un'istanza di java.util.concurrent, è possibile che un thread modifichi l'istanza (cioè mettere un elemento in un hashmap simultaneo) e un thread successivo non vedrà la modifica?

La mia domanda sorge dal fatto che il modello di memoria Java consente ai thread di memorizzare nella cache i valori invece di prenderli direttamente dalla memoria se l'accesso al valore non è sincronizzato.

È stato utile?

Soluzione

Sul pacchetto Java.util.ConCurrent Proprietà di coerenza della memoria, puoi controllare l'API Javadoc per il pacchetto:

I metodi di tutte le classi in java.util.ConCurrent e i suoi sottocampi estendono queste garanzie a sincronizzazione di livello superiore. In particolare:

  • Azioni in un thread prima di posizionare un oggetto in qualsiasi raccolta simultanea accadendo prima Azioni successive all'accesso o alla rimozione di quell'elemento dalla raccolta in un altro thread.
    [...]
  • Azioni prima di "rilasciare" metodi di sincronizzatore come
    Lock.unlock, semaphore.release e
    CountdownLatch.Countdown
    accadendo prima Azioni successive a un metodo di successo "Acquisizione" come blocco.lock, semaphore.acquere, condition.await e countdownlatch.await sullo stesso oggetto Sincronizzatore in un altro thread.
    [...]

Quindi, le classi in questo pacchetto assicurano che la concorrenza, utilizzando una serie di classi per il controllo dei thread (Lock, Semaphore, eccetera.). Queste classi gestiscono il accadendo prima logica a livello di programmazione, cioè gestire una pila FIFO di thread simultanei, bloccare e rilasciare thread di corrente e successivi (cioè usando Thread.wait() e Thread.resume(), eccetera.

Quindi, (teoricamente) non è necessario sincronizzare le tue dichiarazioni accedendo a queste classi, perché controllano a livello di programmazione i thread concorrenti.

Altri suggerimenti

Poiché la concorrenza (ad esempio) è progettata per essere utilizzata da un contesto simultaneo, non è necessario sincronizzarlo ulteriormente. In effetti, farlo potrebbe minare le ottimizzazioni che introduce.

Ad esempio, Collections.SynchronizedMap (...) rappresenta un modo per rendere sicuro un thread della mappa, a quanto ho capito, funziona essenzialmente avvolgendo tutte le chiamate all'interno della parola chiave sincronizzata. Qualcosa come ConcorrentHashmap invece crea "secchi" sincronizzati tra gli elementi della collezione, causando un controllo di concorrenza a grana più fine e quindi dando meno contesa di blocco in uso pesante. Potrebbe anche non bloccare le letture per esempio. Se lo avvolgi di nuovo con un certo accesso sincronizzato, potresti minare questo. Ovviamente, devi stare attento che tutto l'accesso alla raccolta sia sincronizzato ecc. Che è un altro vantaggio della nuova libreria; Non devi preoccuparti (tanto!).

Le raccolte Java.Lang.ConCurrent possono implementare la loro sicurezza del thread tramite sincrhonizzate. nel qual caso la specifica della lingua garantisce la visibilità. Possono implementare le cose senza usare le serrature. Non sono così chiaro su questo, ma presumo che la stessa visibilità sarebbe in atto qui.

Se vedi quelli che sembrano aggiornamenti persi nel tuo codice, potrebbe essere che è solo una condizione di gara. Qualcosa come la ConcorrentHashpMap ti darà il valore più recente in una lettura e la scrittura potrebbe non essere stata ancora scritta. È spesso un compromesso tra precisione e prestazioni.

Il punto è; Java.util.ConCurrent Stuff ha lo scopo di fare queste cose, quindi non dovrebbe essere necessario la visibilità e l'uso della sincronizzazione volatile e/o aggiunta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top