Mise à jour:
Pour toute personne intéressée, ce bug a été résolu et fixe pour Java 7u6 construire b14. Vous pouvez voir le rapport de bug/bugs ici
Réponse Originale À Cette Question
Lorsque l'on pense en termes de mémoire de la visibilité/commande, vous auriez besoin de penser à propos de son-passe-avant la relation. La pré condition pour b != 0
est a == 1
. Si a != 1
alors b peut être 0 ou 1.
Une fois qu'un thread voit a == 1
alors que le thread est garanti pour voir b == 1
.
Post Java 5, dans l'OP exemple, une fois que l' while(a == 0)
éclate b est garantie 1
Edit:
J'ai couru à la simulation nombre de fois et de ne pas voir votre sortie.
Quel système d'exploitation, la version Java & CPU êtes-vous tester?
Je suis sur Windows 7, Java 1.6_24 (essayer avec _31)
Edit 2:
Bravo à l'OP et Walter Laan - Pour moi, il ne s'est passé lorsque je suis passé de 64 bits de Java 32 bits de Java, sur (mais ne peut pas être exclue) une version 64 bits de windows 7.
Edit 3:
La cession tt
, ou plutôt la staticget d' b
semble avoir un impact significatif (pour prouver cette suppression de l' int tt = b;
et il devrait toujours fonctionner.
Il semble que la charge de b
en tt
va stocker le champ localement qui sera ensuite utilisé dans le si coniditonal (la référence à cette valeur non tt
). Donc, si b == 0
est vrai, il est probable que le magasin local d' tt
a 0 (à ce point de sa course à affecter 1 à local tt
). Cela semble être vrai pour les 32 Bits de Java 1.6 & 7 avec l'ensemble de client.
J'ai comparé les deux sortie de l'assemblée et de la différence immédiate était ici. (Gardez à l'esprit ce sont des fragments de code).
Cet imprimé "erreur"
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
Et
Cela n'a pas l'impression "d'erreur"
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
Dans cet exemple, la première entrée est à partir d'une série qui a imprimé "erreur", tandis que le deuxième a été l'un qui na pas.
Il semble que l'exécution de travail chargé et attribué b
correctement avant de le tester égal à 0.
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)
Lors de l'exécution, qui a imprimé "erreur" chargé la version en cache d' %edx
0x021dd75e: cmp $0x0,%edx
0x021dd761: jne 0x021dd788 ;*ifne
; - Test$1::run@13 (line 17)
Pour ceux qui ont plus d'expérience avec l'assembleur veuillez peser :)
Edit 4
Devrait être mon dernier montage, comme la simultanéité dev obtenir une main sur elle, j'ai fait le test avec et sans le
int tt = b;
affectation un peu plus. J'ai constaté que lorsque j'augmente le max de 100 à 1000 il semble y avoir un 100% de taux d'erreur lors de l' int tt = b
est inclus et 0% de chances lorsqu'il n'est pas exclu.