Das Java-Meomry-Modell schreibt vor, dass synchronize
Blöcke, die auf demselben Monitor synchronisieren, eine Vorher-Nachher-Reaktion auf die in diesen Blöcken geänderten Variablen erzwingen. Beispiel:Java-Speichermodell: Neuordnung und gleichzeitige Sperren
// in thread A
synchronized(lock)
{
x = true;
}
// in thread B
synchronized(lock)
{
System.out.println(x);
}
In diesem Fall ist es, dass Garantierter Gewinde B x==true
solange Faden A sehen, dass bereits bestanden synchronized
-block. Jetzt bin ich dabei, viel Code neu zu schreiben, um die flexibleren (und angeblich schneller) Sperren in java.util.concurrent
zu verwenden, insbesondere die ReentrantReadWriteLock
. So sieht das Beispiel wie folgt aus:
EDIT: Das Beispiel war gebrochen, weil ich den Code falsch umgewandelt, wie durch matt b zur Kenntnis genommen. Wie folgt festgesetzt:
// in thread A
lock.writeLock().lock();
{
x = true;
}
lock.writeLock().unlock();
// in thread B
lock.readLock().lock();
{
System.out.println(x);
}
lock.readLock().unlock();
Ich habe jedoch keine Hinweise innerhalb der Speichermodellspezifikation gesehen, die solche Sperren auch die nessessary Ordnung bedeuten. Wenn man sich die Implementierung ansieht, scheint sie auf den Zugriff auf flüchtige Variablen innerhalb von AbstractQueuedSynchronizer
(zumindest für die Sun-Implementierung) zu vertrauen. Dies ist jedoch nicht Teil einer Spezifikation, und außerdem wird der Zugriff auf nichtflüchtige Variablen nicht wirklich als durch die Speicherbarriere dieser Variablen abgedeckt betrachtet, oder?
So, hier sind meine Fragen:
- Ist es sicher, die gleiche Reihenfolge wie bei den „alten“
synchronized
Blöcke zu übernehmen? - Ist das irgendwo dokumentiert?
- Zugriff auf eine flüchtige Variable eine Speicherbarriere für jede andere Variable?
Grüße, Steffen
-
Kommentar zu Yanamon:
Blick auf den folgenden Code:
// in thread a
x = 1;
synchronized (a) { y = 2; }
z = 3;
// in thread b
System.out.println(x);
synchronized (a) { System.out.println(y); }
System.out.println(z);
Von dem, was ich verstanden, erzwingt die Speicherbarriere die zweite Ausgabe zeigt 2, hat aber keinen Einfluss auf die anderen Variablen ...? Wie kann man das mit dem Zugriff auf eine volatile Variable vergleichen?
Ein Hinweis über den Code, den Sie hinzugefügt haben, Thread b wird nur 2 drucken, wenn es die Sperre für einen vor Thread erhält ... das war irgendwie impliziert, aber ich wollte das nur klarstellen. Aber um Sie zu beantworten volatile Frage, flüchtige in folgender Weise verwendet werden, um Sichtbarkeit zu erzwingen: -------- volatile boolean memoryBarrier = false; int unbewachtWert = 0; // Thread a: unguardedValue = 10; memoryBarrier = wahr; // Thread b if (memoryBarrier) { // unguardedValue wird garantiert als 10 gelesen; } – Yanamon
Nun, ich denke, Code in Kommentaren schreiben funktioniert nicht wirklich gut, ich aktualisierte meine Antwort mit einem Beispiel – Yanamon