Gemäß der Java-Sprachspezifikation ( Beispiel 17.4-1 ) das folgende Snippet (beginnend in A == B == 0
) ...
... kann in r2 == 2
und r1 == 1
resultieren. Dies liegt daran, dass das Ergebnis der Ausführung von B = 1;
nicht davon abhängt, ob r2 = A
ausgeführt wurde oder nicht, so dass es der JVM freisteht, die Reihenfolge der Ausführung dieser beiden Anweisungen zu tauschen. Mit anderen Worten, das folgende Interleaving wird von der Spezifikation zugelassen:
was eindeutig zu r2 == 1
und r1 == 1
führt.
Nehmen wir an, wir optimieren das Beispiel etwas:
%Vor% wobei obj
eine Referenz ist, die zwischen den Threads geteilt wird.
Ist die Neuanordnung von r2 = A
und B = 1
noch zulässig?
Die JLS sagt ...
Compiler können jedoch die Anweisungen in beiden Threads neu anordnen, wenn dies die Ausführung dieses Threads nicht isoliert beeinflusst.
... welche Art angibt, dass die Anweisungen noch ausgetauscht werden dürfen. Auf der anderen Seite die folgende Aussage
Es erfolgt eine Entsperrung auf einem Monitor - vor jeder weiteren Sperre auf diesem Monitor.
gibt an, dass wir unter bestimmten Schedulings eine "happen-before" -Beziehung zwischen den Anweisungen in den beiden Threads haben können, was vermutlich die Neuordnung von Anweisungen nicht erlaubt.
Informell ist es nicht erlaubt. Dies ist bekannt als "Roach Motel-Modell"
Insbesondere kann eine Aktion nicht über einen Synchronisationsblock verschoben werden.
Allerdings spricht JMM formal nicht von einer Neuordnung. In Ihrem Beispiel können wir das nur begründen,
entweder ist der Sync-Block 1 vor dem Sync-Block 2 in der Gesamtsynchronisationsreihenfolge, deshalb r2=A
passiert-bevor A=2
; r2
muss 0 sein. Es gibt jedoch keine Einschränkungen zwischen B=1
und r1=B
; r1
kann 0 oder 1 sein.
oder umgekehrt. r1
muss 0 sein, r2
kann 0 oder 2 sein.
So enthält das Programm noch Datenrennen; Trotzdem können wir annehmen, dass (r1,r2)
nur (0,0), (1,0), (0,2) sein kann; es ist unmöglich zu sein (1,2)
Tags und Links java jvm memory-model jls