Aktualisieren:
Für alle Interessierten wurde dieser Fehler behoben und für Java 7u6 Build B14 behoben. Sie können den Fehlerbericht / die Fehlerbehebungen hier sehen
Ursprüngliche Antwort
Wenn Sie in Bezug auf die Sichtbarkeit / Reihenfolge des Gedächtnisses denken, müssen Sie über die Beziehung nachdenken, die vor dem Ereignis besteht. Die wichtige Voraussetzung für b != 0
ist für a == 1
. Wenn a != 1
dann kann b entweder 0 oder 1 sein.
Sobald ein Thread sieht, a == 1
wird dieser Thread garantiert sehen b == 1
.
Post Java 5, im OP-Beispiel, sobald der while(a == 0)
Ausbruch b garantiert 1 ist
Bearbeiten:
Ich habe die Simulation viele Male ausgeführt und Ihre Ausgabe nicht gesehen.
Unter welchem Betriebssystem, welcher Java-Version und welcher CPU testen Sie?
Ich bin unter Windows 7, Java 1.6_24 (versuche es mit _31)
Bearbeiten 2:
Ein großes Lob an das OP und Walter Laan - Für mich geschah dies nur, als ich von 64-Bit-Java auf 32-Bit-Java auf einem 64-Bit-Windows 7 umstieg (aber nicht ausgeschlossen werden darf).
Edit 3:
Die Zuordnung zu tt
oder vielmehr das Statikget von b
scheint einen signifikanten Einfluss zu haben (um dies zu beweisen, entfernen Sie dasint tt = b;
und es sollte immer funktionieren.
Es scheint, dass das Laden von b
in tt
das Feld lokal speichert, das dann im if-Koniditon verwendet wird (der Verweis auf diesen Wert nicht tt
). Wenn dies b == 0
zutrifft, bedeutet dies wahrscheinlich, dass der lokale Speicher tt
0 war (zu diesem Zeitpunkt ist es ein Rennen , dem lokalen Speicher 1 zuzuweisen tt
). Dies scheint nur für 32-Bit-Java 1.6 & 7 mit festgelegtem Client zu gelten.
Ich habe die beiden Ausgangsbaugruppen verglichen und der unmittelbare Unterschied war hier. (Denken Sie daran, dies sind Ausschnitte).
Dieser gedruckte "Fehler"
0x021dd753: test %eax,0x180100 ; {poll}
0x021dd759: cmp $0x0,%ecx
0x021dd75c: je 0x021dd748 ;*ifeq
; - Test$1::run@7 (line 13)
0x021dd75e: cmp $0x0,%edx
0x021dd761: jne 0x021dd788 ;*ifne
; - Test$1::run@13 (line 17)
0x021dd767: nop
0x021dd768: jmp 0x021dd7b8 ; {no_reloc}
0x021dd76d: xchg %ax,%ax
0x021dd770: jmp 0x021dd7d2 ; implicit exception: dispatches to 0x021dd7c2
0x021dd775: nop ;*getstatic out
; - Test$1::run@16 (line 18)
0x021dd776: cmp (%ecx),%eax ; implicit exception: dispatches to 0x021dd7dc
0x021dd778: mov $0x39239500,%edx ;*invokevirtual println
Und
Dies druckte nicht "Fehler"
0x0226d763: test %eax,0x180100 ; {poll}
0x0226d769: cmp $0x0,%edx
0x0226d76c: je 0x0226d758 ;*ifeq
; - Test$1::run@7 (line 13)
0x0226d76e: mov $0x341b77f8,%edx ; {oop('Test')}
0x0226d773: mov 0x154(%edx),%edx ;*getstatic b
; - Test::access$0@0 (line 3)
; - Test$1::run@10 (line 17)
0x0226d779: cmp $0x0,%edx
0x0226d77c: jne 0x0226d7a8 ;*ifne
; - Test$1::run@13 (line 17)
0x0226d782: nopw 0x0(%eax,%eax,1)
0x0226d788: jmp 0x0226d7ed ; {no_reloc}
0x0226d78d: xchg %ax,%ax
0x0226d790: jmp 0x0226d807 ; implicit exception: dispatches to 0x0226d7f7
0x0226d795: nop ;*getstatic out
; - Test$1::run@16 (line 18)
0x0226d796: cmp (%ecx),%eax ; implicit exception: dispatches to 0x0226d811
0x0226d798: mov $0x39239500,%edx ;*invokevirtual println
In diesem Beispiel stammt der erste Eintrag aus einem Lauf, der "Fehler" druckte, während der zweite aus einem Lauf stammte, der dies nicht tat.
Es scheint, dass der Arbeitslauf b
vor dem Testen korrekt geladen und zugewiesen wurde und gleich 0 ist.
0x0226d76e: mov $0x341b77f8,%edx ; {oop('Test')}
0x0226d773: mov 0x154(%edx),%edx ;*getstatic b
; - Test::access$0@0 (line 3)
; - Test$1::run@10 (line 17)
0x0226d779: cmp $0x0,%edx
0x0226d77c: jne 0x0226d7a8 ;*ifne
; - Test$1::run@13 (line 17)
Während des Laufs, der "Fehler" druckte, wurde die zwischengespeicherte Version von geladen %edx
0x021dd75e: cmp $0x0,%edx
0x021dd761: jne 0x021dd788 ;*ifne
; - Test$1::run@13 (line 17)
Für diejenigen, die mehr Erfahrung mit Assembler haben, wiegen Sie bitte :)
Bearbeiten 4
Sollte meine letzte Bearbeitung sein, da die Parallelitätsentwickler eine Hand darauf bekommen, habe ich mit und ohne die int tt = b;
Aufgabe noch etwas mehr getestet
. Ich fand heraus, dass wenn ich das Maximum von 100 auf 1000 erhöhe, es eine 100% ige Fehlerrate zu geben scheint, wenn int tt = b
es eingeschlossen ist, und eine 0% ige Chance, wenn es ausgeschlossen ist.
b
nicht synchronisiert werden .b=1
a