Ich habe Multithreading in Java gelesen und bin darauf gestoßen
Lokale Variablen sind in Java threadsicher.
Seitdem habe ich darüber nachgedacht, wie / warum lokale Variablen threadsicher sind.
Kann mir bitte jemand Bescheid geben?
Ich habe Multithreading in Java gelesen und bin darauf gestoßen
Lokale Variablen sind in Java threadsicher.
Seitdem habe ich darüber nachgedacht, wie / warum lokale Variablen threadsicher sind.
Kann mir bitte jemand Bescheid geben?
Antworten:
Wenn Sie einen Thread erstellen, wird ein eigener Stapel erstellt. Zwei Threads haben zwei Stapel und ein Thread teilt seinen Stapel niemals mit einem anderen Thread.
Allen in Ihrem Programm definierten lokalen Variablen wird Speicher im Stapel zugewiesen (Wie Jatin kommentierte, bedeutet Speicher hier Referenzwert für Objekte und Wert für primitive Typen) (Jeder Methodenaufruf eines Threads erstellt einen Stapelrahmen auf seinem eigenen Stapel). Sobald die Ausführung der Methode durch diesen Thread abgeschlossen ist, wird der Stapelrahmen entfernt.
Auf youtube gibt es einen großartigen Vortrag von Stanford-Professor, der Ihnen beim Verständnis dieses Konzepts helfen kann.
Lokale Variablen werden im eigenen Stapel jedes Threads gespeichert. Das bedeutet, dass lokale Variablen niemals von Threads gemeinsam genutzt werden. Das bedeutet auch, dass alle lokalen primitiven Variablen threadsicher sind.
public void someMethod(){
long threadSafeInt = 0;
threadSafeInt++;
}
Lokale Verweise auf Objekte sind etwas anders. Die Referenz selbst wird nicht geteilt. Das Objekt, auf das verwiesen wird, wird jedoch nicht im lokalen Stapel jedes Threads gespeichert. Alle Objekte werden im gemeinsam genutzten Heap gespeichert. Wenn ein lokal erstelltes Objekt der Methode, in der es erstellt wurde, niemals entgeht, ist es threadsicher. Tatsächlich können Sie es auch an andere Methoden und Objekte weitergeben, solange keine dieser Methoden oder Objekte das übergebene Objekt anderen Threads zur Verfügung stellt
Denken Sie an Methoden wie Definitionen von Funktionalität. Wenn zwei Threads dieselbe Methode ausführen, sind sie in keiner Weise miteinander verbunden. Sie erstellen jeweils eine eigene Version jeder lokalen Variablen und können in keiner Weise miteinander interagieren.
Wenn Variablen nicht lokal sind (wie Instanzvariablen, die außerhalb einer Methode auf Klassenebene definiert wurden), werden sie an die Instanz angehängt (nicht an einen einzelnen Lauf der Methode). In diesem Fall sehen zwei Threads, die dieselbe Methode ausführen, die eine Variable, und dies ist nicht threadsicher.
Betrachten Sie diese beiden Fälle:
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;
}
}
Im ersten Fall NotThreadsafe
sehen zwei Threads, die auf derselben Instanz von ausgeführt werden, dasselbe x. Dies könnte gefährlich sein, da die Threads versuchen, x zu ändern! Im zweiten Fall Threadsafe
sehen zwei Threads, die auf derselben Instanz von ausgeführt werden, völlig unterschiedliche Variablen und können sich nicht gegenseitig beeinflussen.
Jeder Methodenaufruf hat seine eigenen lokalen Variablen, und natürlich findet ein Methodenaufruf in einem einzelnen Thread statt. Eine Variable, die nur von einem einzelnen Thread aktualisiert wird, ist von Natur aus threadsicher.
Allerdings hält, ein wachsames Auge auf , was genau damit gemeint ist: nur die Schreibvorgänge auf die Variable selbst Thread-sicher ist ; Das Aufrufen von Methoden für das Objekt, auf das es verweist, ist nicht von Natur aus threadsicher . Gleiches gilt für die direkte Aktualisierung der Objektvariablen.
Neben den anderen Antworten wie Nambaris.
Ich möchte darauf hinweisen, dass Sie eine lokale Variable in einer anoymösen Typmethode verwenden können:
Diese Methode kann in anderen Threads aufgerufen werden, wodurch die Thread-Sicherheit beeinträchtigt werden kann. Daher erzwingt Java, dass alle lokalen Variablen, die in anoymösen Typen verwendet werden, als endgültig deklariert werden.
Betrachten Sie diesen illegalen Code:
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();
}
}
Wenn Java dies zulässt (wie C # dies durch "Closures" tut), wäre eine lokale Variable nicht mehr unter allen Umständen threadsicher. In diesem Fall ist der Wert von i
am Ende aller Threads nicht garantiert 100
.
Der Thread hat einen eigenen Stapel. Zwei Threads haben zwei Stapel und ein Thread teilt seinen Stapel niemals mit einem anderen Thread. Lokale Variablen werden im eigenen Stapel jedes Threads gespeichert. Das bedeutet, dass lokale Variablen niemals von Threads gemeinsam genutzt werden.
Grundsätzlich gibt es in Java vier Arten von Speicher, um Klasseninformationen und Daten zu speichern:
Methodenbereich, Heap, JAVA-Stapel, PC
Der Methodenbereich und der Heap werden also von allen Threads gemeinsam genutzt, aber jeder Thread hat seinen eigenen JAVA-Stack und PC und dieser wird von keinem anderen Thread gemeinsam genutzt.
Jede Methode in Java ist als Stapelrahmen. Wenn also eine Methode von einem Thread aufgerufen wird, wird dieser Stapelrahmen auf seinen JAVA-Stapel geladen. Alle lokalen Variablen, die in diesem Stapelrahmen und dem zugehörigen Operandenstapel vorhanden sind, werden von anderen nicht gemeinsam genutzt. Der PC verfügt über Informationen zur nächsten Anweisung, die im Bytecode der Methode ausgeführt werden soll. Daher sind alle lokalen Variablen THREAD SAFE.
@ Weston hat auch eine gute Antwort gegeben.
Auf dem Thread-Stack werden nur lokale Variablen gespeichert.
Die lokale Variable , das ist primitive type
(zB int, long ...) auf dem gespeicherten thread stack
und als Ergebnis - anderer Thread keinen Zugriff darauf hat.
Lokale Variable , die reference type
(Nachfolger von Object
) ist, enthält aus 2 Teilen - Adresse (die gespeichert ist thread stack
) und das Objekt (das gespeichert ist 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;
}