Sind nicht synchronisierte statische Methoden threadsicher, wenn sie statische Klassenvariablen nicht ändern?

145

Ich frage mich , ob Sie eine statische Methode, die ist nicht synchronisiert, aber nicht nicht ändern , dass statische Variablen ist es Thread-sicher? Was ist, wenn die Methode lokale Variablen darin erstellt? Ist der folgende Code beispielsweise threadsicher?

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

Wenn ich also zwei Threads habe, die diese Methode kontinuierlich und gleichzeitig aufrufen, einen mit Hunden (sagen wir "Deutsche Dogge" und "Bullenhund") und den anderen mit Katzen (sagen wir "Perser" und "Siamesen"), werde ich jemals Katzen und Hunde bekommen im gleichen Array? Oder werden sich die Katzen und Hunde niemals gleichzeitig im selben Aufruf der Methode befinden?

Schlitten
quelle
Ein weiterer Thread zu diesem Thema: stackoverflow.com/questions/8015797/…
象 嘉 道
2
Das ist eine andere Frage. Dies ist, ob der statische Methodenaufruf threadsicher ist und nicht, ob Arrays vorhanden sind.
Schlitten

Antworten:

212

Diese Methode ist 100% threadsicher, selbst wenn dies nicht der Fall wäre static. Das Problem mit der Thread-Sicherheit tritt auf, wenn Sie Daten zwischen Threads austauschen müssen - Sie müssen auf Atomizität, Sichtbarkeit usw. achten.

Diese Methode verarbeitet nur Parameter, die sich auf dem Stapel befinden und auf unveränderliche Objekte auf dem Heap verweisen. Der Stapel ist von Natur aus lokal für den Thread , sodass niemals Daten gemeinsam genutzt werden.

Unveränderliche Objekte ( Stringin diesem Fall) sind ebenfalls threadsicher, da sie nach ihrer Erstellung nicht mehr geändert werden können und alle Threads denselben Wert sehen. Wenn die Methode andererseits akzeptiert (veränderlich) wäre, hätten DateSie möglicherweise ein Problem gehabt. Zwei Threads können gleichzeitig dieselbe Objektinstanz ändern, was zu Rennbedingungen und Sichtbarkeitsproblemen führt.

Tomasz Nurkiewicz
quelle
4
Korrekte Antwort. Variablen auf Methodenebene werden in jedem Thread-Ausführungsstapel repliziert.
Sid
Technisch gesehen ist die Methode inline und die Parameter sind CPU-Register. Trotzdem ist die Antwort richtig
am
43
Der Stapel ist natürlich lokal für den aktuellen Thread, aber Sie können Verweise auf freigegebene Objekte auf diesem Stapel haben. Dies ist im Beispiel kein Problem, da Strings unveränderlich sind. Eine Methode, die einen übergebenen Parameter ändert, kann jedoch Probleme mit der Thread-Sicherheit haben, wenn auf dieses übergebene Objekt von mehreren Threads aus zugegriffen werden kann.
Jörn Horstmann
1
Wie @TomaszNurkiewicz erwähnte, können wir, wenn wir eine veränderbare Objektreferenz übergeben, in Rennbedingungen geraten. Gilt dies auch dann, wenn die Methode das Objekt in keiner Weise ändert? Ich meine, wird es immer noch als Rassenbedingung eingestuft, weil das Objekt veränderlich war? Und was ist, wenn wir den Parametern das letzte Schlüsselwort hinzufügen?
Rafay
Was ist, wenn ich ein Klassenobjekt in der Methode übergebe? Wird die Variable im Stapel oder Haufen?
grep
28

Eine Methode kann nur threadsicher sein, wenn sie einen gemeinsam genutzten Status ändert. Ob es statisch ist oder nicht, spielt keine Rolle.

Konrad Garus
quelle
3
@Konrad_Garus Die Frage hier war, ob lokale Variablen einen gemeinsam genutzten Status darstellen oder nicht oder ob der Stapel für eine statische Methode pro Thread oder gemeinsam genutzt wurde.
Schlitten
"Eine Methode kann nur threadsicher sein, wenn sie einen gemeinsamen Status ändert." Nein, es kann auch Thread-unsicher sein, wenn es lediglich auf den freigegebenen Status zugreift, ohne ihn zu ändern. Der nicht synchronisierte Zugriff auf ein veränderbares Objekt kann auf den inkonsistenten Status zugreifen, wenn das Objekt von einem anderen Thread mutiert wird, selbst wenn der andere Thread ordnungsgemäß synchronisiert ist. Beide Threads müssen entsprechend synchronisiert werden, damit die Thread-Sicherheit gewährleistet ist.
Warren Dew
12

Die Funktion ist absolut threadsicher.

Wenn Sie darüber nachdenken ... nehmen Sie an, was passieren würde, wenn dies anders wäre. Jede übliche Funktion hätte Threading-Probleme, wenn sie nicht synchronisiert würde. Daher müssten alle API-Funktionen im JDK synchronisiert werden, da sie möglicherweise von mehreren Threads aufgerufen werden könnten. Und da die App die meiste Zeit eine API verwendet, wären Multithread-Apps praktisch unmöglich.

Das ist zu lächerlich, um darüber nachzudenken, also nur für Sie: Methoden sind nicht threadsicher, wenn es einen klaren Grund gibt, warum es Probleme geben könnte. Versuchen Sie immer darüber nachzudenken, was passiert, wenn mehrere Threads in meiner Funktion vorhanden sind und was passiert, wenn Sie einen Step-Debugger haben und Schritt für Schritt den ersten ... dann den zweiten Thread ... vielleicht den zweiten wieder voranbringen ... würde es Probleme geben? Wenn Sie eine finden, ist sie nicht threadsicher.

Beachten Sie auch, dass die meisten Java 1.5 Collection-Klassen nicht threadsicher sind, mit Ausnahme der angegebenen Klassen wie ConcurrentHashMap.

Und wenn Sie wirklich darauf eingehen möchten, schauen Sie sich das flüchtige Schlüsselwort und ALLE seine Nebenwirkungen genau an. Schauen Sie sich die Klassen Semaphore () und Lock () sowie ihre Freunde in java.util.Concurrent an. Lesen Sie alle API-Dokumente rund um die Klassen. Es lohnt sich auch zu lernen und zu befriedigen.

Entschuldigen Sie diese übermäßig ausführliche Antwort.

Daniel
quelle
2
"Wenn Sie darüber nachdenken ... nehmen Sie an, was passieren würde, wenn dies anders wäre. Jede übliche Funktion hätte Threading-Probleme, wenn sie nicht synchronisiert würde, sodass alle API-Funktionen im JDK synchronisiert werden müssten, da sie möglicherweise von mehreren aufgerufen werden könnten Fäden. " Guter Punkt!
Schlitten
1

Verwenden Sie das staticSchlüsselwort mit synchronisierten statischen Methoden, um statische Daten zu ändern, die von Threads gemeinsam genutzt werden. Mit dem staticSchlüsselwort kämpfen alle erstellten Threads um eine einzelne Version der Methode.

Wenn Sie das volatileSchlüsselwort zusammen mit synchronisierten Instanzmethoden verwenden, wird sichergestellt, dass jeder Thread über eine eigene Kopie der gemeinsam genutzten Daten verfügt und keine Lese- / Schreibvorgänge zwischen den Threads auftreten.

Clinton
quelle
0

Die Unveränderlichkeit von String-Objekten ist ein weiterer Grund für das oben beschriebene thread-sichere Szenario. Wenn stattdessen veränderbare Objekte verwendet werden (z. B. makeMutableArray ..), wird die Thread-Sicherheit mit Sicherheit unterbrochen.

hart
quelle
Die Frage war, ob ein statischer Methodenaufruf jemals die Argumente eines anderen Aufrufs derselben Methode von einem anderen Thread sehen würde. Die Antwort ist ein klares "Nein!". Das wusste ich, wollte es aber zweifelhaften Mitarbeitern beweisen können.
Schlitten
Warum wurde diese Antwort abgelehnt? Der Punkt, der von den anderen Antworten nicht beigesteuert wird, ist, dass die Veränderlichkeit ein- oder ausgehend sein kann. Wenn Sie eine veränderbare Datei zurückgeben, sind Sie nicht threadsicher. Die Frage stellt ihre Frage nicht so eng, wie es der Kommentar nahelegt; Die erweiterte Frage nach dem Codebeispiel hätte im Code ausgedrückt werden können, möglicherweise als Komponententest. Aber ich sympathisiere mit dem Versuch, Mitarbeiter zu überzeugen. "Sie glauben mir oder meinem Testcode oder Josh Bloch nicht, aber vielleicht akzeptieren sie eine Antwort auf SO."
Som-Snytt