Le comportement de faire une référence non volatile à un objet volatile en Java


Venant de C/C++, je suis un peu confus au sujet du comportement des objets volatils en Java.

Je comprends que volatile en Java a deux propriétés:

  1. N'apportera pas d'objet dans le cache, gardez-le toujours dans la mémoire principale.
  2. Garantie "arriver-avant"

Cependant, je ne sais pas ce qui se passe si je fais une nouvelle référence non volatile à object. Par exemple,

class Example {
   private volatile Book b = null;

   public init() { b = new Book(...); }

   public use() {
     Book local = b;
     local.read();
   }
}

AFAIK, volatile signifie que l ' "objet livre" auquel b fait référence doit être dans la mémoire principale. Le compilateur implémente probablement la référence en tant que pointeur en interne, donc le pointeur b se trouve probablement dans le cache. Et à ma connaissance, volatile est un qualificatif pour object, pas pour reference/pointer.

La question est: dans la méthode use, la référence locale n'est pas volatile. Cette référence " locale "amènerait-elle l'objet Livre sous-jacent de la mémoire principale dans le cache, rendant essentiellement l'objet non"volatil"?

Author: Oliver Young, 2018-01-19

2 answers

Il n'y a pas de garantie "objet volatil" ni "toujours le garder en mémoire principale".

Tout ce que volatilevariables d'une garantie de type de référence, c'est qu'il y aura une relation happens-before entre une écriture sur cette variable et une lecture ultérieure de la même variable.

Puisque se produit-avant que les relations ne soient transitives, elles fonctionnent pour votre exemple de code, c'est-à-dire pour b = new Book(...) toutes les modifications apportées à l'instance Book sont validées avant que la référence ne soit écrite dans b et donc pour Book local = b; local.read();, le read() est garanti de voir toutes ces modifications effectuées par l'autre thread avant d'écrire la référence.

Cela n'implique pas que la mémoire de l'instance Book était spéciale. Par exemple, les modifications apportées à l'instance après que la référence a été écrite vers b peuvent ou non être visibles par d'autres threads et d'autres threads peuvent ne percevoir que certains d'entre eux ou les voir comme s'ils étaient faits dans un autre ordre.

Donc, peu importe la façon dont vous obtenez la référence à l'objet, tout ce qui compte est de savoir si les modifications sont apportées avant ou après la publication d'une référence à cet objet via b. De même, peu importe comment vous effectuez l'accès en lecture à l'objet, tant que vous le faites après avoir acquis la référence en lisant b.

Avec local.read(); vous accédez à l'objet via la variable locale {[11] } et dans read(), la même référence sera accessible bien que this, mais tout ce qui compte, c'est que vous ayez acquis la référence en lisant b avant de lire l'état de l'objet.

 4
Author: Holger, 2018-01-19 10:44:12

volatile concerne la référence, pas l'objet.

Il garantit que tout thread lisant la variable b après qu'un autre thread a défini la valeur de b obtiendra la valeur assignée à b par l'autre thread, et non une valeur mise en cache.

 2
Author: JB Nizet, 2018-01-19 08:14:20