2010-12-03 36 views
4
  • Ce qui m'intrigue c'est ça.

Java doc de HashEntry dans ConcurrentHashMap (jdk1.6.0_16)Lors d'une course de données, un thread peut-il lire la valeur nulle initiale de la variable volatile? surtout quand une valeur non nulle lui est assignée dans le constructeur?

... Parce que le champ de valeur est volatile WRT, pas définitive, il est légal le modèle Java mémoire pour un lecteur non synchronisé pour voir null au lieu de la valeur initiale lors de la lecture via une course de données. Bien qu'un réarrangement menant à cela ne se produise probablement jamais, la méthode Segment.readValueUnderLock est utilisée comme sauvegarde dans le cas où une valeur nulle (pré-initialisée) est jamais vue dans une méthode d'accès non synchronisée.

  • ici est la mise en œuvre de la méthode get de ConcurrentHashMap # Segment

    
    V get(Object key, int hash) { 
         if (count != 0) { // read-volatile 
          HashEntry e = getFirst(hash); 
          while (e != null) { 
           if (e.hash == hash && key.equals(e.key)) { 
            V v = e.value; 
            if (v != null) 
             return v; 
            return readValueUnderLock(e); // recheck 
           } 
           e = e.next; 
          } 
         } 
         return null; 
        } 
    
  • Et readValueUnderLock


V readValueUnderLock(HashEntry e) { 
     lock(); 
     try { 
      return e.value; 
     } finally { 
      unlock(); 
     } 
    } 
  • Sur la base de ma lecture et la compréhension de chaque fil volonté lire une valeur à jour de la variable volatile.

  • Alors, quand un thread lit-il une valeur nulle initiale? en particulier dans HashEntry où la valeur est assignée avant que le constructeur ne l'achève. (A noter également que la référence de HashEntry n'échappe à son constructeur.)

  • Je suis perplexe, quelqu'un peut expliquer le doc java ci-dessus HashEntry dans ConcurrentHashMap (jdk1.6.0_16). et pourquoi ce verrouillage supplémentaire de précaution est nécessaire?

+0

À quoi ressemble votre constructeur? Est-ce qu'il fuit des références avant qu'il se termine? Sinon, tout ira bien. – Gabe

+0

Comme je l'ai déjà mentionné dans ma question (deuxième dernier point). "Notez également que la référence de HashEntry n'échappe jamais à son constructeur". Je n'ai pas passé le code ici, pour réduire l'encombrement et parce que c'était un simple constructeur d'affectation. – Jigar

Répondre

3

Lorsque Java 1.5 a été libéré, il y avait une disposition dans le JMM qui stipulait que le HashEntry pouvait être partiellement initialisé. C'est-à-dire, lorsqu'un thread est mis dans la carte, le HashEntry est créé et assigné en tant que référence à la tête du bucket ou à un membre collison. À ce moment-là, la valeur de l'entrée n'a peut-être pas été attribuée aux autres threads.

Le CHM suppose que si l'entrée n'est pas nulle, la valeur ne doit pas être nulle, readValueUnderLock a donc été placé comme sécurité intégrée.

J'ai demandé à DL sur cette situation exacte et il a dit que malgré la possibilité que cela se produise, il ne devrait jamais. Il a également dit que depuis le 1.6, ce problème ne se produira pas.

+0

Je présume que "DL" est Doug Lea. – Darron

+0

Oui, désolé. Doug Lea –

0

Vous devez vous assurer que la référence à la carte ne peut être utilisée par personne, avant que le constructeur ne l'ait terminée. Cela devrait être facile à faire quand il s'agit d'un champ privé et uniquement accessible par les méthodes getter - y compris dans la classe où ce champ est tenu.

Le constructeur se termine avant que la méthode getter de l'instance puisse être appelée.

+0

Le constructeur termine avant d'accéder au champ. Ce n'est pas mon code, c'est de la bibliothèque java.util.concurrent de base. Ils ont veillé à ce que la référence ne s'échappe pas. Mais ce qui m'intrigue, c'est leur commentaire java doc, et le soin supplémentaire qu'ils ont pris pour acquérir un verrou si la valeur est nulle. Pourquoi Pourquoi ??? – Jigar

+0

Hmm ... Lire encore ceci semble un peu étrange en effet ... –