Statisches Methodenverhalten in einer Multithread-Umgebung in Java

114

Es gibt eine einfache dumme Frage, die mich stört und in meinem Kopf mehrere Argumente vorbringt. Ich möchte alle Zweifel an den folgenden Fragen ausräumen.

class Clstest{

    public static String testStaticMethod(String inFileStr) {

        // section 0

        // section 1

        // do something with inFileStr

        // section 2

        // section 3

        return inFileStr;

    }

}

Nehmen wir an, es gibt fünf Threads, die jeweils gleichzeitig einen Aufruf ausführen Clstest.testStaticMethod("arg-n").

Thread 1 ruft auf Clstest.testStaticMethod("arg-1").

Wenn sich Thread 1 in Abschnitt 1 befindet, ruft Thread 2 auf Clstest.testStaticMethod("arg-2").

Was passiert dann mit Thread 1? Wird es in den Schlafzustand gehen?

Wenn Thread 1 die Chance hat, wird die Ausführung von Abschnitt 1 fortgesetzt, in dem sie angehalten wurde?

Wie passiert es, wenn alle fünf Threads ein Clstest.testStaticMethodund dasselbe Clstest.testStaticMethodgemeinsam nutzen?

Gibt es eine Möglichkeit, die inFileStrvon mehreren Threads gesendeten auszutauschen?

namalfernandolk
quelle
Auf welche Sprache zielen Sie ab?
ΩmegaMan
3
@ OmegaMan: Es ist Java
Namalfernandolk

Antworten:

192

Die Antwort von Hans Passant ist gut. Aber ich dachte, ich würde versuchen, es jedem, der darauf stößt und neu in Java ist, auf einer etwas einfacheren Ebene zu erklären. Hier geht..

Der Speicher in Java ist in zwei Arten unterteilt - den Heap und die Stacks. Auf dem Haufen leben alle Objekte und auf den Stapeln erledigen die Threads ihre Arbeit. Jeder Thread hat seinen eigenen Stapel und kann nicht auf die Stapel des anderen zugreifen. Jeder Thread hat auch einen Zeiger auf den Code, der auf das Codebit zeigt, das gerade ausgeführt wird.

Wenn ein Thread eine neue Methode ausführt, speichert er die Argumente und lokalen Variablen in dieser Methode auf einem eigenen Stapel. Einige dieser Werte können Zeiger auf Objekte auf dem Heap sein. Wenn zwei Threads dieselbe Methode gleichzeitig ausführen, zeigen beide ihre Codezeiger auf diese Methode und haben ihre eigenen Kopien von Argumenten und lokalen Variablen auf ihren Stapeln. Sie stören sich nur, wenn die Dinge auf ihren Stapeln auf dieselben Objekte auf dem Haufen zeigen. In diesem Fall können alle möglichen Dinge passieren. Aber wie Hans betont, sind Strings unveränderlich (können nicht geändert werden), sodass wir sicher sind, wenn dies das einzige Objekt ist, das "geteilt" wird.

So viele Threads können dieselbe Methode ausführen. Sie werden möglicherweise nicht gleichzeitig ausgeführt. Dies hängt davon ab, wie viele Kerne sich auf Ihrem Computer befinden, da die JVM Java-Threads Betriebssystem-Threads zuordnet, die auf Hardware-Threads geplant sind. Sie haben daher wenig Kontrolle darüber, wie diese Threads verschachtelt sind, ohne komplexe Synchronisationsmechanismen zu verwenden.

Beachten Sie, dass das Schlafen etwas ist, was ein Thread sich selbst antut.

selig
quelle
3
In einer Multi-Core-Prozessorumgebung gibt es möglicherweise mehrere Threads, die denselben Code gleichzeitig ausführen, nicht wahr? In einer Einzelprozessorumgebung wird jeweils nur ein Thread ausgeführt. (Mehrere Threads teilen sich die Zeit zwischen ihnen.) Wenn der Thread-Zeitplan die Chance vom aktuellen auslaufenden Thread (A) zum Thread (B) gibt, wie wird der Thread (A) dort fortgesetzt, wo er angehalten wurde? Ich meine, woher kennt es den Lebenslaufpunkt? Liegt es an "Jeder Thread hat auch einen Zeiger in den Code, der auf das Codebit zeigt, das er gerade ausführt?" wie du gesagt hast?
Namalfernandolk
6
Du hast es. Nur um einige Punkte zu verdeutlichen: Erstens liegt es außerhalb der Kontrolle von Java, wie Threads geplant werden. Ich spreche hier von Suns Hotspot JVM. Die JVM ordnet einen Java-Thread einem Betriebssystem-Thread zu und das Betriebssystem entscheidet, welche Threads ausgeführt werden sollen. Wie Sie sagen, kann das Betriebssystem auf einem Single-Core-Computer jeweils nur einen ausführen, auf einem Multicore-Computer jedoch möglicherweise mehrere gleichzeitig. Zweitens weiß ein Thread nicht genau, wann er angehalten wird. Die einzige Information, die er hat, ist der Programmzeiger (der Zeiger in den Code) und der Stapel, die genau so gespeichert und wiederhergestellt werden, wie sie waren.
Selig
Inter-Thread-Interferenzen treten also auf, wenn Threads Variablen außerhalb ihres lokalen Bereichs verwenden und beispielsweise ein Thread den Wert der Variablen aktualisiert, bevor ein anderer Thread diese Variable (oder den Zeiger auf die Variable) auf seinem eigenen Stapel abruft. Ist das ein richtiges Verständnis?
Hariszhr
2
Um etwas genauer zu sein ... Interferenzen können nur auftreten und können auftreten, werden aber nicht unbedingt auftreten ... wenn Threads Dinge auf dem Heap gemeinsam nutzen (nicht lokal). Es gibt verschiedene Möglichkeiten, wie Interferenzen auftreten können, die von den Abhängigkeiten zwischen verschiedenen Teilen des Codes abhängen. Ich bin mir bei Ihrem Beispiel nicht sicher, da einige Details fehlen. Möglicherweise beziehen Sie sich auf ein potenzielles Problem, bei dem die Threads A und B einen gemeinsam genutzten Wert lesen und ihn dann basierend auf dem gelesenen Wert aktualisieren. Dies ist ein Datenrennen.
Selig
1
@selig Wenn ich eine Klasse mit nur Instanzmethoden habe, zum Beispiel: eine Serviceklasse und es ist Singleton, dann muss ich mir keine Sorgen machen, dass mehrere Threads die Instanzmethoden gleichzeitig ausführen, da die Serviceklasse keinen Status enthält, in dem Status ist nur vorhanden, wenn die Klasse Instanzvariablen hat. Ist mein Verständnis richtig?
Yug Singh
67

Wird es in den Schlafzustand gehen?

Nein, das Ausführen eines Threads wirkt sich nicht auf andere Threads aus, solange diese nicht absichtlich miteinander synchronisiert werden. Wenn Sie mehr als einen Prozessorkern haben, wie dies bei allen neueren Computern der Fall ist, werden diese Threads wahrscheinlich genau zur gleichen Zeit ausgeführt. Dies ist etwas weniger wahrscheinlich, wenn Sie 5 Threads starten, da Ihr Computer möglicherweise nicht über genügend Kerne verfügt. Das Betriebssystem ist gezwungen, zwischen ihnen zu wählen, sodass sie jeweils etwas Zeit zum Ausführen haben. Der Job des Thread-Schedulers. Ein Thread befindet sich dann nicht im Ruhezustand. Er wird einfach angehalten und wartet darauf, dass der Thread-Scheduler ihm die Möglichkeit gibt, ausgeführt zu werden. Es wird dort fortgesetzt, wo es vom Scheduler unterbrochen wurde.

Gibt es eine Möglichkeit, das von mehreren Threads gesendete inFileStr auszutauschen?

Es gibt keine solche Möglichkeit, Threads haben einen eigenen Stapel, sodass jedes Methodenargument und jede lokale Variable für jeden Thread eindeutig ist. Die Verwendung eines Strings garantiert außerdem, dass diese Threads sich nicht gegenseitig stören können, da Strings unveränderlich sind.

Es gibt keine solche Garantie, wenn das Argument auf eine andere Art von veränderlichem Objekt verweist. Oder wenn die Methode selbst statische Variablen verwendet oder auf Objekte auf dem Heap verweist. Die Synchronisierung ist erforderlich, wenn ein Thread das Objekt ändert und ein anderer Thread es liest. Das Schlüsselwort lock in der Sprache C # ist die Möglichkeit, die erforderliche Synchronisierung zu implementieren. Die Tatsache, dass die Methode statisch ist, bedeutet nicht, dass eine solche Synchronisation niemals erforderlich ist. Wahrscheinlich nur weniger , da Sie müssen nicht über Gewinde sorgen das gleiche Objekt zugreifen (gemeinsame Nutzung dieses ).

Hans Passant
quelle
3
Hoppla, ich habe das [Java] -Tag nie gesehen. Nahe genug.
Hans Passant
Ich habe vergessen hinzuzufügen, als es veröffentlicht wurde. Mein Fehler. :). Trotzdem danke für die Antwort. Es war sehr hilfreich.
Namalfernandolk