Warum sind lokale Variablen in Java threadsicher?

90

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?

Anand
quelle
27
Weil sie im Stapel zugeordnet sind. Und Threads teilen sich nicht den Stapel. Es ist einzigartig für jeden.
Rohit Jain

Antworten:

102

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.

kosa
quelle
13
Es tut mir leid, Sie liegen falsch, nur primitive lokale Variablen werden auf dem Stapel gespeichert. Rest alle Variablen werden auf Heap gespeichert. Java 7 führte eine Escape-Analyse ein, die für einige Variablen möglicherweise im Stapel zugeordnet wird
Jatin
6
Der Stapel enthält nur den Verweis auf das Objekt auf dem Heap. Da der Stapel gelöscht wird, wird auch die Referenz gelöscht. Daher ist es für die Müllabfuhr verfügbar
Jatin
6
@Jatin: Du bist richtig. Wenn ich Speicher meinte, meine ich Referenzwert für Objekte und Werte für Grundelemente (ich denke, unerfahrene Entwickler wissen auch, dass sich Objekte auf dem Haufen befinden).
kosa
2
@Nambari aber wenn der Referenzwert auf eine gemeinsam genutzte Variable zeigt. Wie können wir dann sagen, dass es threadsicher ist?
H. Rabiee
3
@hajder: Was macht eine Variable als gemeinsam genutzt? von dort aus starten. Entweder Instanz- oder Klassenvariablen, oder? keine lokalen Variablen UND lesen Sie Marko Toplink Antwort in diesem Thread, ich denke, das ist der Punkt, über den Sie verwirrt sind.
kosa
19

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

Renjith
quelle
Es gibt einen Fehler in agrument, bitte schauen Sie sich die Kommentare von @Nambari Antwort
Jatin
Wenn Sie auf die Tatsache hinweisen, dass localSafeInt immer nur 0, dann 1 und dann trotzdem gelöscht ist, ist das gut. Es zeigt also, dass diese Variable nicht von Threads gemeinsam genutzt wird und dadurch nicht von Multithreading betroffen ist. Ich denke, Sie könnten ein wenig mehr darauf hinweisen, dass threadsicher immer nur 0 oder 1 ist
bis zum
14

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 NotThreadsafesehen 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 Threadsafesehen zwei Threads, die auf derselben Instanz von ausgeführt werden, völlig unterschiedliche Variablen und können sich nicht gegenseitig beeinflussen.

Cory Kendall
quelle
6

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.

Marko Topolnik
quelle
1
Sie sagen, "das Aufrufen von Methoden für das Objekt, auf das es verweist, ist nicht von Natur aus threadsicher". Aber wie kann das Objekt, auf das durch eine lokale Methodenreferenz verwiesen wird - instanziiert in diesem Methodenbereich - von zwei Threads gemeinsam genutzt werden? Könnten Sie anhand eines Beispiels darauf hinweisen?
Akshay Lokur
1
Eine lokale Variable kann ein Objekt enthalten oder nicht, das innerhalb des Methodenbereichs instanziiert wurde und nicht Teil der Frage war. Selbst wenn dies der Fall ist, kann die Methode auf den freigegebenen Status zugreifen.
Marko Topolnik
6

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 iam Ende aller Threads nicht garantiert 100.

Weston
quelle
Hallo Weston, Aus der obigen Diskussion und den folgenden Antworten habe ich verstanden, dass Java die Thread-Sicherheit für alle lokalen Variablen gewährleistet. Darf ich wissen, wie das synchronisierte Schlüsselwort dann tatsächlich verwendet wird? Könnten Sie bitte mit einem Beispiel wie diesem erklären.
Prabhu
5

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.

Sudhirkumar Murkute
quelle
3

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.

Prashant
quelle
1

Auf dem Thread-Stack werden nur lokale Variablen gespeichert.

Die lokale Variable , das ist primitive type(zB int, long ...) auf dem gespeicherten thread stackund 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;
}

Geben Sie hier die Bildbeschreibung ein

yoAlex5
quelle