Stavo leggendo il multi-threading in Java e mi sono imbattuto in questo
Le variabili locali sono thread-safe in Java.
Da allora ho pensato come / perché le variabili locali sono thread-safe.
Qualcuno può farmelo sapere.
Stavo leggendo il multi-threading in Java e mi sono imbattuto in questo
Le variabili locali sono thread-safe in Java.
Da allora ho pensato come / perché le variabili locali sono thread-safe.
Qualcuno può farmelo sapere.
Risposte:
Quando crei un thread, verrà creato il proprio stack. Due thread avranno due stack e un thread non condivide mai lo stack con un altro thread.
Tutte le variabili locali definite nel programma verranno allocate in memoria nello stack (come ha commentato Jatin, memoria qui significa valore di riferimento per gli oggetti e valore per i tipi primitivi) (Ogni chiamata al metodo da parte di un thread crea uno stack frame sul proprio stack). Non appena l'esecuzione del metodo viene completata da questo thread, lo stack frame verrà rimosso.
C'è una grande lezione del professore di Stanford su YouTube che può aiutarti a comprendere questo concetto.
Le variabili locali vengono memorizzate nello stack di ogni thread. Ciò significa che le variabili locali non vengono mai condivise tra i thread. Ciò significa anche che tutte le variabili primitive locali sono thread-safe.
public void someMethod(){
long threadSafeInt = 0;
threadSafeInt++;
}
I riferimenti locali agli oggetti sono leggermente diversi. Il riferimento stesso non è condiviso. L'oggetto a cui si fa riferimento, tuttavia, non viene archiviato nello stack locale di ogni thread. Tutti gli oggetti vengono archiviati nell'heap condiviso. Se un oggetto creato localmente non sfugge mai al metodo in cui è stato creato, è thread-safe. In effetti puoi anche passarlo ad altri metodi e oggetti purché nessuno di questi metodi o oggetti renda l'oggetto passato disponibile ad altri thread
Pensa a metodi come definizioni di funzionalità. Quando due thread eseguono lo stesso metodo, non sono in alcun modo correlati. Ciascuno di loro creerà la propria versione di ciascuna variabile locale e non sarà in grado di interagire in alcun modo.
Se le variabili non sono locali (come le variabili di istanza definite al di fuori di un metodo a livello di classe), vengono associate all'istanza (non a una singola esecuzione del metodo). In questo caso, due thread che eseguono lo stesso metodo vedono entrambi l'unica variabile e questo non è thread-safe.
Considera questi due casi:
public class NotThreadsafe {
int x = 0;
public int incrementX() {
x++;
return x;
}
}
public class Threadsafe {
public int getTwoTimesTwo() {
int x = 1;
x++;
return x*x;
}
}
Nel primo, due thread in esecuzione sulla stessa istanza di NotThreadsafe
vedranno la stessa x. Questo potrebbe essere pericoloso, perché i thread stanno cercando di cambiare x! Nel secondo, due thread in esecuzione sulla stessa istanza di Threadsafe
vedranno variabili completamente diverse e non possono influenzarsi a vicenda.
Ogni chiamata di metodo ha le sue variabili locali e, ovviamente, una chiamata di metodo avviene in un singolo thread. Una variabile che viene aggiornata solo da un singolo thread è intrinsecamente thread-safe.
Tuttavia , tieni d'occhio cosa si intende esattamente con questo: solo le scritture sulla variabile stessa sono thread-safe; la chiamata di metodi sull'oggetto a cui fa riferimento non è intrinsecamente thread-safe . Lo stesso vale per l'aggiornamento diretto delle variabili dell'oggetto.
Oltre alle altre risposte come quella di Nambari.
Vorrei sottolineare che puoi usare una variabile locale in un metodo di tipo anonimo:
Questo metodo potrebbe essere chiamato in altri thread che potrebbero compromettere la sicurezza del thread, quindi java forza tutte le variabili locali utilizzate in tipi anonimi da dichiarare come finali.
Considera questo codice illegale:
public void nonCompilableMethod() {
int i=0;
for(int t=0; t<100; t++)
{
new Thread(new Runnable() {
public void run() {
i++; //compile error, i must be final:
//Cannot refer to a non-final variable i inside an
//inner class defined in a different method
}
}).start();
}
}
Se Java lo consentisse (come fa C # tramite le "chiusure"), una variabile locale non sarebbe più sicura per i thread in tutte le circostanze. In questo caso, i
non è garantito che il valore di alla fine di tutti i thread sia 100
.
Il thread avrà il proprio stack. Due thread avranno due stack e un thread non condivide mai lo stack con un altro thread. Le variabili locali vengono memorizzate nello stack di ogni thread. Ciò significa che le variabili locali non vengono mai condivise tra i thread.
Fondamentalmente ci sono quattro tipi di archiviazione in Java per memorizzare informazioni e dati sulla classe:
Area del metodo, Heap, Stack JAVA, PC
quindi l'area del metodo e l'heap sono condivisi da tutti i thread ma ogni thread ha il proprio stack JAVA e PC e non è condiviso da nessun altro thread.
Ogni metodo in java è come Stack frame. quindi, quando un metodo viene chiamato da un thread, lo stack frame viene caricato sul suo stack JAVA. Tutte le variabili locali presenti in quello stack frame e lo stack di operandi correlato non sono condivise da altri. Il PC avrà le informazioni della prossima istruzione da eseguire nel codice byte del metodo. quindi tutte le variabili locali sono THREAD SAFE.
@Weston ha anche dato una buona risposta.
Solo le variabili locali vengono memorizzate nello stack di thread.
La variabile locale che è primitive type
(ad esempio int, long ...) è memorizzata su thread stack
e, di conseguenza, l'altro thread non ha accesso ad essa.
La variabile locale che è reference type
(successore di Object
) contiene da 2 parti: indirizzo (su cui è memorizzato thread stack
) e oggetto (su cui è memorizzato heap
)
class MyRunnable implements Runnable() {
public void run() {
method1();
}
void method1() {
int intPrimitive = 1;
method2();
}
void method2() {
MyObject1 myObject1 = new MyObject1();
}
}
class MyObject1 {
MyObject2 myObject2 = new MyObject2();
}
class MyObject2 {
MyObject3 myObject3 = MyObject3.shared;
}
class MyObject3 {
static MyObject3 shared = new MyObject3();
boolean b = false;
}