Question

il est mentionné dans le modèle de mémoire Java que :Lorsqu'un thread quitte un bloc synchronisé dans le cadre de la libération du moniteur associé, le JMM exige que le cache du processeur local soit vidé vers la mémoire principale.De la même manière, dans le cadre de l'acquisition du moniteur lors de l'entrée dans un bloc synchronisé, les caches locaux sont invalidés afin que les lectures ultérieures aillent directement dans la mémoire principale et non dans le cache local.

alors pourquoi dans ce code je dois déclarer l'instance comme volatile puisque lorsque le deuxième thread entre dans le bloc de synchronisation, il ira directement dans la mémoire principale ??

public final class MySingleton {
  private static MySingleton instance = null;
  private MySingleton() { } 
  public static MySingleton getInstance() {
    if (instance == null) {
      synchronized (MySingleton.class) {
        if (instance == null) {
          instance = new MySingleton();
        }
      }
    }
    return instance;
  }
}

Je veux dire, lorsqu'un autre thread entre dans le bloc de synchronisation et effectue la deuxième vérification, il est censé être mis à jour à partir de la mémoire principale, comme mentionné.

Était-ce utile?

La solution

La condition de course est la suivante :

  1. Le fil A voit instance == NULL et exécute ce code instance = new MySingleton();.L'écriture à instance est visible mais l'écrit dans MySingleton ne le sont pas encore.

  2. Le fil B voit instance != NULL et commence à travailler sur l'instance.

  3. Le thread B travaille maintenant sur un objet dont il ne peut pas voir la construction.

Fabrication instance volatile résout le problème car la spécification de la mémoire du JDK, à partir du JDK5, garantit que les écritures sur des objets non volatiles ne seront pas vues dans le désordre par rapport à une écriture sur un objet volatile.Donc, n'importe quel fil qui voit instance != NULL doit voir l'instance elle-même.

Autres conseils

Vous devez le déclarer volatils, sinon il n'y a aucune garantie que deux appels à Geinstance () renvoient le même exemple.

Il n'y a aucune garantie que la mémoire principale sera accessible, seule une valeur cohérente au cache.c'est-à-dire que tous les threads verront la même valeur.

BTW: Vous savez bien sûr, c'est bien plus complexe que nécessaire.Tout ce dont vous avez besoin est

public enum MySingleton {
     INSTANCE;
}

fait beaucoup la même chose.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top