I thread con metodi statici non sincronizzati sono sicuri se non modificano le variabili di classe statiche?


145

Mi chiedevo se hai un metodo statico che non è sincronizzato, ma non modifica alcuna variabile statica è sicuro per i thread? Che dire se il metodo crea variabili locali al suo interno? Ad esempio, il codice seguente è thread-safe?

public static String[] makeStringArray( String a, String b ){
    return new String[]{ a, b };
}

Quindi, se ho due thread che chiamano questo metodo continuamente e contemporaneamente, uno con i cani (diciamo "great dane" e "bull dog") e l'altro con i gatti (diciamo "persiano" e "siamese") otterrò mai cani e gatti nello stesso array? O i cani e i gatti non saranno mai nella stessa invocazione del metodo contemporaneamente?


un altro thread su questo problema: stackoverflow.com/questions/8015797/…
象 嘉

2
Questa è una domanda diversa, è se l'invocazione del metodo statico è thread-safe, non se gli array lo sono.
Slitta del

Risposte:


212

Questo metodo è sicuro al 100%, anche se non lo fosse static . Il problema con la sicurezza dei thread sorge quando è necessario condividere i dati tra i thread: è necessario occuparsi di atomicità, visibilità, ecc.

Questo metodo funziona solo su parametri, che risiedono su stack e riferimenti a oggetti immutabili su heap. Lo stack è intrinsecamente locale nel thread , quindi non si verifica mai la condivisione dei dati.

Gli oggetti immutabili ( Stringin questo caso) sono anche thread-safe perché una volta creati non possono essere modificati e tutti i thread vedono lo stesso valore. D'altra parte se il metodo accettasse (mutabile) Datesi sarebbe potuto avere un problema. Due thread possono modificare contemporaneamente la stessa istanza dell'oggetto, causando condizioni di competizione e problemi di visibilità.


4
Risposta corretta. Le variabili a livello di metodo vengono replicate in ogni stack di esecuzione del thread.
Sid

tecnicamente il metodo deve essere integrato e i parametri saranno i registri della CPU. Tuttavia la risposta è corretta
bestsss

43
Lo stack è ovviamente locale al thread corrente, ma è possibile avere riferimenti a oggetti condivisi su quello stack. Questo non è un problema nell'esempio poiché le stringhe sono immutabili, ma un metodo che modifica un parametro passato può avere problemi di sicurezza del thread se questo oggetto passato è accessibile da più thread.
Jörn Horstmann,

1
Come accennato da @TomaszNurkiewicz, se passiamo un riferimento all'oggetto mutabile, possiamo entrare nelle condizioni di gara. Questo vale anche se il metodo non cambia l'oggetto in alcun modo? Voglio dire, sarà ancora classificato come condizione di razza perché l'oggetto era mutabile? E se aggiungessimo la parola chiave finale ai parametri?
Rafay,

Cosa succede se passo oggetto di classe nel metodo? Sarà il varaible nello stack o heap?
grep,

28

Un metodo può essere pericoloso per i thread solo quando cambia uno stato condiviso. Che sia statico o meno è irrilevante.


3
@Konrad_Garus La domanda qui era sulla falsariga se le variabili locali costituissero o meno uno stato condiviso o se lo stack di un metodo statico fosse per thread o condiviso.
Slitta

"Un metodo può essere sicuro per i thread solo quando cambia uno stato condiviso." No, può anche essere un thread non sicuro se accede semplicemente allo stato condiviso senza modificarlo. L'accesso non sincronizzato a un oggetto mutabile può accedere a uno stato incoerente se l'oggetto viene mutato da un altro thread, anche se l'altro thread è sincronizzato correttamente. Entrambi i thread richiedono una sincronizzazione appropriata per mantenere la sicurezza dei thread.
Warren Dew,

12

La funzione è perfettamente thread-safe.

Se ci pensate ... supponiamo che cosa accadrebbe se questo fosse diverso. Ogni normale funzione avrebbe problemi di threading se non sincronizzata, quindi tutte le funzioni API nel JDK dovrebbero essere sincronizzate, perché potrebbero essere chiamate da più thread. E poiché la maggior parte delle volte l'app utilizza alcune API, le app multithread sarebbero effettivamente impossibili.

Questo è troppo ridicolo per pensarci, quindi solo per te: i metodi non sono sicuri se c'è una ragione chiara per cui potrebbero esserci problemi. Cerca di pensare sempre a cosa succederebbe se ci fossero più thread nella mia funzione, e cosa succederebbe se avessi un debugger e un passo dopo l'altro avanzi il primo ... poi il secondo thread ... forse il secondo di nuovo ... ci sarebbero problemi? Se ne trovi uno, non è sicuro per i thread.

Si noti inoltre che la maggior parte delle classi Collection 1.5 di Java non sono thread-safe, ad eccezione di quelle dove indicato, come ConcurrentHashMap.

E se vuoi davvero immergerti in questo, dai un'occhiata da vicino alla parola chiave volatile e TUTTI i suoi effetti collaterali. Dai un'occhiata alla classe Semaphore () e Lock () e ai loro amici in java.util.Concurrent. Leggi tutti i documenti API relativi alle classi. Vale la pena di imparare e anche soddisfacente.

Ci scusiamo per questa risposta eccessivamente elaborata.


2
"Se ci pensate ... supponiamo che cosa accadrebbe se questo fosse diverso. Ogni normale funzione avrebbe problemi di threading se non sincronizzata, quindi tutte le funzioni API nel JDK dovrebbero essere sincronizzate, perché potrebbero essere chiamate da più fili ". Buon punto!
Slitta

1

Utilizzare la staticparola chiave con metodi statici sincronizzati per modificare i dati statici condivisi tra i thread. Con la staticparola chiave tutti i thread creati contenderanno una singola versione del metodo.

Utilizzare la volatileparola chiave insieme a metodi di istanza sincronizzati garantirà che ogni thread disponga di una propria copia dei dati condivisi e che non vi siano perdite di lettura / scrittura tra i thread.


0

Gli oggetti stringa immutabili sono un altro motivo per lo scenario thread-safe sopra. Invece se vengono usati oggetti mutabili (diciamo makeMutableArray ..), sicuramente la sicurezza del thread si romperà.


La domanda era se una chiamata a un metodo statico avrebbe mai visto gli argomenti di un'altra chiamata allo stesso metodo da un altro thread. La risposta è un clamoroso "no!". Questo, lo sapevo, ma volevo essere in grado di dimostrare ai colleghi dubbiosi.
Slitta

Perché questa risposta è stata sottovalutata? Il punto, non fornito dalle altre risposte, è che la mutabilità potrebbe essere in -bound o out-bound. Se restituisci un oggetto modificabile, non sei sicuro del thread. La domanda non pone la domanda in modo così limitato come suggerisce il commento; la domanda estesa dopo l'esempio di codice avrebbe potuto essere espressa in codice, forse come unit test. Ma sono solidale con il tentativo di convincere i colleghi. "Non mi credono, né il mio codice di prova, o Josh Bloch, ma forse accetteranno una risposta su SO."
som-snytt,
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.