Je pense par exemple de volatile dans la spécification Java est un peu mal.
Dans 8.3.1.4. Les champs volatils, il est dit
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}
... puis méthode en deux temps en temps pourrait imprimer une valeur pour j qui est supérieure à la valeur de i, parce que l'exemple ne comprend pas la synchronisation et, selon les règles expliquées in§17.4, les valeurs partagées de i et j peuvent être mis à jour sur commande.
Je pense que même si ces mises à jour sont dans l' ordre, la méthode peut encore deux voir j plus que moi, puisque System.out.println("i=" + i + " j=" + j)
n'est pas atomique, et i est lu avant j.
Procédé selon deux est la même que
read i
read j
Il est donc possible que
read i
i++
j++
read j
Dans ce cas, la méthode de deux voir une valeur pour j qui est supérieure à i, mais les mises à jour ne sont pas hors de l'ordre.
Donc, de l'ordre n'est pas la seule raison de voir j> i
Devrait - il être System.out.println("j=" + j + " i=" + i);
?
Cette fois hors d'usage est la seule raison de voir j> i
Les exemples sont plus que « un peu mal ».
Tout d' abord, vous avez raison que , même sans réordonnancement, j
peut apparaître plus que i
dans cet exemple. Ceci est même reconnu plus tard dans le même exemple :
Une autre approche serait de déclarer
i
etj
d'êtrevolatile
:class Test { static volatile int i = 0, j = 0; static void one() { i++; j++; } static void two() { System.out.println("i=" + i + " j=" + j); } }
Cela permet à la méthode
one
et la méthodetwo
à exécuter en même temps, mais garantit que les accès aux valeurs partagées pouri
etj
se produisent exactement autant de fois, et dans le même ordre, comme ils semblent se produire lors de l' exécution du texte du programme par chaque fil. Par conséquent, la valeur partagéej
est jamais supérieure à celle pouri
, parce que chaque mise à jouri
doit se refléter dans la valeur partagéei
avant la mise à jourj
se produit. Il est possible, cependant, que toute invocation donnée de la méthodetwo
peut observer une valeurj
bien supérieure à la valeur observée pouri
, parce que la méthodeone
peut être exécuté plusieurs fois entre le moment où la méthodetwo
va chercher la valeur dei
et le moment où la méthodetwo
récupère la valeur dej
.
Bien sûr, il est abstruse de dire « la valeur partagée j
est jamais supérieure à celle pouri
», juste pour dire droit dans la phrase suivante « Il est possible ... [à] observer une valeur j
bien supérieure à la valeur observée pouri
».
Donc , j
ne dépasse jamais i
, sauf quand il est observé que beaucoup plus grand que i
? Est - il censé dire que « un peu plus » est impossible?
Bien sûr que non. Cette déclaration n'a pas de sens et semble être le résultat d'essayer de séparer une vérité objective comme « la valeur partagée » de « la valeur observée » alors qu'en fait, il n'y a qu'un comportement observable dans un programme.
Ceci est illustré par la phrase erronée:
Cela permet à la méthode et de méthode de deux à exécuter en même temps, mais garantit que les accès aux valeurs partagées pour
i
etj
se produisent exactement autant de fois, et dans le même ordre, comme ils semblent se produire lors de l' exécution du texte du programme par chaque fil.
Même avec les volatile
variables, il n'y a aucune garantie. Tout ce que la machine virtuelle Java doit garantir, est que le comportement observé ne contredit pas la spécification, de sorte que lorsque vous invoquez one()
mille fois dans une boucle, par exemple, un optimiseur peut toujours remplacer avec un incrément atomique par des milliers, si elle peut empêcher la possibilité d'un autre thread témoin de la présence d'une telle optimisation (autre que déduisant de la vitesse plus élevée).
En d' autres termes, combien de fois est qu'accède, n'est pas observable et , par conséquent, non spécifié une variable (resp. Son emplacement de mémoire). Peu importe de toute façon. Tout ce qui est important pour un programmeur d'application, est que j
peut être supérieur à i
, si les variables sont déclarées volatile
ou non.
Permutant l'ordre du lit de i
et à l' j
intérieur two()
pourrait faire un meilleur exemple, mais je pense, il serait préférable, si JLS §8.3.1.2 n'a pas essayé d'expliquer la signification des volatile
familièrement, mais juste dit qu'il impose une sémantique spéciale selon au modèle de mémoire et de gauche à la JMM pour l' expliquer de manière formellement correcte.
Les programmeurs ne sont pas censés maître juste concurrency en lisant 8.3.1.4, si l'exemple est inutile ici. (Dans le meilleur des cas, le pire des cas serait de créer l'impression que cet exemple était suffisante pour comprendre la question).