it-swarm.com.de

Ist ein flüchtiges int in Java threadsicher?

Ist ein flüchtiger int in Java-Thread-sicher? Kann also ohne Sperren sicher gelesen und beschrieben werden?

49
shawn

Ja, Sie können sicher davon lesen und schreiben - aber Sie können nichts Zusammenfügen, wie das sichere Inkrementieren, da dies ein Lese-, Änderungs- und Schreibzyklus ist. Es geht auch darum, wie es mit dem Zugriff auf andere - Variablen interagiert.

Die genaue Natur der Volatilität ist offenkundig verwirrend (siehe Abschnitt zum Speichermodell der JLS für weitere Details ) - Ich würde persönlich generell AtomicInteger verwenden, als einfacheren Weg dafür zu sorgen, dass ich es richtig mache.

63
Jon Skeet

[...] als ob man ohne Sperren sicher lesen und schreiben kann?

Ja, ein Lesevorgang führt immer zum Wert des letzten Schreibvorgangs (und sowohl Lese- als auch Schreibvorgänge sind atomare Operationen).

Ein flüchtiges Lesen/Schreiben führt bei der Ausführung eine so genannte "happen-before" -Zusammensetzung ein.

Aus der Java-Sprachspezifikation Kapitel 17: Threads und Sperren

Ein Schreibvorgang in ein flüchtiges Feld (§8.3.1.4) erfolgt vor jedem nachfolgenden Lesen dieses Feldes.

Mit anderen Worten, beim Umgang mit flüchtigen Variablen müssen Sie nicht explizit mit dem Schlüssel synchronized eine Synchronisation durchführen (einführen, bevor Sie eine Beziehung einfügen), um sicherzustellen, dass der Thread den neuesten Wert in die Variable schreibt.

Jon Skeet weist jedoch darauf hin, dass die Verwendung von flüchtigen Variablen begrenzt ist, und Sie sollten generell die Verwendung von Klassen aus dem Java.util.concurrent-Paket in Betracht ziehen.

6
aioobe

Der Zugriff auf volatile int in Java ist Thread-sicher. Wenn ich Zugriff sage, meine ich die Einheitsoperation darüber, wie zB volatile_var = 10 oder int temp = volatile_var (im Wesentlichen schreiben/lesen mit konstanten Werten). Das volatile Keyword in Java sorgt für zwei Dinge:

  1. Beim Lesen erhalten Sie immer den Wert im Hauptspeicher. Im Allgemeinen verwendet JVM zu Optimierungszwecken Register oder allgemeiner lokaler Speicher für das Speichern/Zugreifen von Variablen. In einer Umgebung mit mehreren Threads kann jeder Thread eine andere Kopie der Variablen sehen. Wenn Sie es jedoch flüchtig machen, wird sichergestellt, dass das Schreiben in die Variable in den Hauptspeicher gespült wird und das Lesen in den Hauptspeicher erfolgt. Dies stellt sicher, dass der Thread die rechte Kopie der Variablen sieht.
  2. Der Zugriff auf das flüchtige Material wird automatisch synchronisiert. So sorgt JVM für eine Reihenfolge beim Lesen und Schreiben der Variablen.

Jon Skeet erwähnt jedoch zu Recht, dass bei nicht-atomaren Operationen (volatile_var = volatile + 1) verschiedene Threads unerwartete Ergebnisse erzielen können.

2
Saurabh

1) Wenn zwei Threads sowohl eine gemeinsam genutzte Variable lesen als auch schreiben, reicht es nicht aus, das volatile-Schlüsselwort dafür zu verwenden. Sie müssen in diesem Fall eine Synchronisierung verwenden, um sicherzustellen, dass das Lesen und Schreiben der Variablen atomar ist. Das Lesen oder Schreiben einer flüchtigen Variablen blockiert weder das Lesen noch das Schreiben von Threads. Dazu müssen Sie das synchronisierte Schlüsselwort in kritischen Abschnitten verwenden.

2) Alternativ zu einem synchronisierten Block können Sie auch einen der vielen atomaren Datentypen verwenden, die im Paket Java.util.concurrent enthalten sind. Zum Beispiel AtomicLong oder AtomicReference oder eine der anderen.

Es ist Thread-sicher, wenn Sie einen Writer-Thread und mehrere Reader-Threads haben.

class Foo {
private volatile Helper helper = null;
public Helper getHelper() {
if (helper == null) {
synchronized(this) {
if (helper == null)
helper = new Helper();
}
}
return helper;
}
}

Hinweis: Wenn Helper unveränderlich ist, ist kein flüchtiges Schlüsselwort erforderlich. Hier funktioniert Singleton ordnungsgemäß. 

Bei einem Zähler, der von mehreren Threads inkrementiert wird (Lesen des Schreibvorgangs), wird keine korrekte Antwort gegeben. Dieser Zustand wird auch durch den Rennzustand veranschaulicht.

public class Counter{
private volatile int i;
public int increment(){
i++;
}
}

HINWEIS: Hier hilft Volatile nicht.

0
Rahul Saxena

Wenn ein flüchtiger Datenträger nicht von einer anderen flüchtigen Variablen abhängig ist, ist sein Thread für den Lesevorgang sicher. Im Falle des Schreibens garantiert flüchtiges nicht die Gewindesicherheit.

Angenommen, Sie haben eine Variable i, die flüchtig ist und deren Wert von einer anderen flüchtigen Variablen, beispielsweise j, abhängig ist. Nun greift Thread-1 auf die Variable j zu und inkrementiert sie und aktualisiert sie gerade aus dem CPU-Cache im Hauptspeicher. Falls der Thread-2 das liest
Variable i bevor Thread-1 das j im Hauptspeicher tatsächlich aktualisieren kann. Der Wert von i entspricht dem alten Wert von j, der falsch wäre. Es wird auch Dirty Read genannt.

0
Ajay Verma

Nicht immer. 

Es ist nicht threadsicher, wenn mehrere Threads die Variable schreiben und lesen. Es ist Thread-sicher, wenn Sie einen Writer-Thread und mehrere Reader-Threads haben. 

Wenn Sie sicher nach Thread suchen, verwenden Sie AtomicXXX classes

Ein kleines Toolkit von Klassen, die die sperrenfreie Thread-sichere Programmierung einzelner Variablen unterstützen. 

Im Wesentlichen erweitern die Klassen in diesem Paket die Vorstellung von flüchtigen Werten, Feldern und Arrayelementen auf diejenigen, die auch eine atomare bedingte Aktualisierungsoperation des Formulars bereitstellen:

boolean compareAndSet(expectedValue, updateValue);

Siehe @teto antworten im nachstehenden Beitrag:

Volatile boolean vs AtomicBoolean

0
Ravindra babu