Java Memory Model: Neuordnung und gleichzeitige Sperren

8

Das Java-Meymry-Modell schreibt vor, dass synchronize -Bausteine, die auf demselben Monitor synchronisiert werden, eine Vorher-Nachher-Umsetzung der Variablen, die in diesen Blöcken geändert wurden, erzwingen. Beispiel:

%Vor%

In diesem Fall wird garantiert, dass Thread B x==true angezeigt wird, solange Thread A diesen synchronized -Block bereits übergeben hat. Jetzt bin ich dabei, viel Code neu zu schreiben, um die flexibleren (und besser gesagt: schnelleren) Sperren in java.util.concurrent zu verwenden, insbesondere die ReentrantReadWriteLock . So sieht das Beispiel so aus:

BEARBEITEN : Das Beispiel war kaputt, weil ich den Code falsch umgesetzt habe, wie in matt b beschrieben. Wie folgt behoben:

%Vor%

Ich habe jedoch in der Spezifikation des Speichermodells keine Hinweise gesehen, dass solche Sperren auch die Notwendigkeit einer Bestellung implizieren. Wenn man sich die Implementierung ansieht, scheint sie sich auf den Zugriff auf flüchtige Variablen in AbstractQueuedSynchronizer zu verlassen (zumindest für die Sun-Implementierung). Dies ist jedoch nicht Teil einer Spezifikation und darüber hinaus wird der Zugriff auf nichtflüchtige Variablen nicht wirklich berücksichtigt, die durch die durch diese Variablen gegebene Speicherbarriere abgedeckt wird, oder?

Also, hier sind meine Fragen:

  • Ist es sicher, dieselbe Reihenfolge anzunehmen wie bei den "alten" synchronized Blöcken?
  • Ist das irgendwo dokumentiert?
  • Greift auf eine flüchtige Variable eine Speicherbarriere für eine andere Variable zu?

Grüße,   Steffen

-

Kommentar zu Yanamon:

Sehen Sie sich den folgenden Code an:

%Vor%

Nach dem, was ich verstanden habe, erzwingt die Speicherbarriere die zweite Ausgabe, um 2 zu zeigen, hat aber keinen garantierten Einfluss auf die anderen Variablen ...? Wie kann man das mit dem Zugriff auf eine flüchtige Variable vergleichen?

    
Steffen Heil 05.04.2010, 00:36
quelle

4 Antworten

5

Aus dem API-Dokument :

  

Alle Lock-Implementierungen müssen erzwungen werden   die gleiche Speichersynchronisation   Semantik wie von der eingebauten bereitgestellt   Monitorsperre, wie in The   Java-Sprachspezifikation, Dritter   Edition (17.4 Speichermodell):

%Vor%      

Erfolgloses Sperren und Entsperren   Operationen und Wiedereintritt   Sperren / Entsperren, nicht   erfordern eine Speichersynchronisierung   Effekte.

    
Dirk 05.04.2010, 00:43
quelle
4

Abgesehen von der Frage, was die Semantik des Speichermodells garantiert, denke ich, dass es einige Probleme mit dem Code gibt, den Sie veröffentlichen.

  1. Sie synchronisieren zweimal in derselben Sperre - dies ist nicht erforderlich. Wenn Sie eine Lock -Implementierung verwenden, müssen Sie den synchronized -Block nicht verwenden.
  2. Das Standard-Idiom für die Verwendung von Lock besteht darin, dies in einem try-finally-Block zu tun, um ein versehentliches Entsperren des Schlosses zu verhindern (da die Sperre nicht automatisch bei der Eingabe eines Blocks aufgehoben wird, wie bei% co_de) % Block).

Sie sollten synchronized mit etwas ähnlichem verwenden:

%Vor%     
matt b 05.04.2010 01:10
quelle
1

Das Lesen und Schreiben von flüchtigen Variablen, die jetzt erzwungen werden, geschieht vor und nach der Operation. Das Schreiben in eine flüchtige Variable hat die gleiche Wirkung wie das Freigeben eines Monitors und das Lesen einer Variablen hat den Effekt, einen Monitor zu erfassen. Das folgende Beispiel macht es ein wenig klarer:

%Vor%

Aber das alles gesagt, der von Ihnen bereitgestellte Beispielcode sah nicht so aus, als ob er wirklich ReentrantLock , wie es entwickelt wurde, um verwendet zu werden.

  1. Die Verwendung eines Lock mit dem integrierten Java-Code syncronized macht den Zugriff auf das Schloss bereits single-threaded, so dass es dem Lock nicht die Chance gibt, wirklich etwas zu tun.
  2. Eine Freigabe von Lock sollte gemäß dem folgenden Muster erfolgen. Dies wird in den Java-Dokumenten von %Co_de%
%Vor%
Yanamon 05.04.2010 01:11
quelle
1

Yanamon, ich bin mir nicht sicher, ob Sie Recht haben - aber aus anderen Gründen als der Argumentation, die Sie machen.

Die Variable unguardedVariable kann im Thread "a" so neu angeordnet werden, dass ihr Wert auf 10 gesetzt wird, nachdem memoryBarrier auf true gesetzt wurde.

"Es gibt keine Garantie, dass Operationen in einem Thread in der vom Programm angegebenen Reihenfolge ausgeführt werden, solange die Neuordnung nicht innerhalb des Threads - erkannt wird, selbst wenn die Reihenfolge neu festgelegt wird ist offensichtlich für andere Threads "

Java Parallelität in der Praxis, Brian Goetz, p34

AKTUALISIERT: Was ich gesagt habe, stimmt im Falle des alten Speichermodells. Also, wenn du einmal-irgendwo-schreiben willst, dann steht mein Argument. In dem neuen Speichermodell ist dies jedoch nicht der Fall, da die Semantik, die die Neuordnung von nicht-flüchtigen Variablen bei Vorhandensein von flüchtigem Zugriff umgibt, strenger geworden ist (siehe Ссылка ).

    
Phillip Henry 30.10.2010 13:02
quelle