web-dev-qa-db-fra.com

Quel est l'intérêt de rendre l'instance singleton volatile lors de l'utilisation du double verrouillage?

private volatile static Singleton uniqueInstance

Dans un singleton lors de l'utilisation de la méthode de double verrouillage pour la synchronisation, pourquoi l'instance unique est-elle déclarée volatile? Puis-je obtenir la même fonctionnalité sans la déclarer volatile?

35
Phoenix

Sans volatile, le code ne fonctionne pas correctement avec plusieurs threads.

De Wikipédia Verrouillage vérifié :

Depuis J2SE 5.0, ce problème a été corrigé. Le mot clé volatile garantit désormais que plusieurs threads gèrent correctement l'instance singleton. Ce nouvel idiome est décrit dans La déclaration "Le verrouillage à double vérification est rompu" :

// Works with acquire/release semantics for volatile
// Broken under Java 1.4 and earlier semantics for volatile
class Foo {
    private volatile Helper helper = null;
    public Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(this) {
                result = helper;
                if (result == null) {
                    helper = result = new Helper();
                }
            }
        }
        return result;
    }

    // other functions and members...
}

En général, vous devriez éviter le double contrôle du verrouillage si possible, car il est difficile de corriger et si vous vous trompez, il peut être difficile de trouver l'erreur. Essayez plutôt cette approche plus simple:

Si l'objet d'assistance est statique (un par chargeur de classe), une alternative est le initialisation sur l'idiome du titulaire de la demande

// Correct lazy initialization in Java 
@ThreadSafe
class Foo {
    private static class HelperHolder {
       public static Helper helper = new Helper();
    }

    public static Helper getHelper() {
        return HelperHolder.helper;
    }
}
27
Mark Byers

volatile empêche la réécriture des écritures en mémoire, ce qui empêche les autres threads de lire les champs non initialisés de votre singleton via le pointeur du singleton.

Considérez cette situation: le thread A découvre que uniqueInstance == null, verrouille, confirme qu'il s'agit toujours de null et appelle le constructeur de singleton. Le constructeur effectue une écriture dans le membre XYZ à l'intérieur de Singleton et retourne. Le thread A écrit maintenant la référence au singleton nouvellement créé dans uniqueInstance et se prépare à libérer son verrou.

Tout comme le thread A s'apprête à libérer son verrou, le thread B arrive et découvre que uniqueInstance n'est pas null. Le fil B accède uniqueInstance.XYZ pensant qu'il a été initialisé, mais parce que le CPU a réorganisé les écritures, les données que le thread A a écrites dans XYZ n'ont pas été rendues visibles au thread B. Par conséquent, le thread B voit une valeur incorrecte à l'intérieur XYZ, ce qui est faux.

Lorsque vous marquez uniqueInstance volatile, une barrière de mémoire est insérée. Toutes les écritures initiées avant celle de uniqueInstance seront terminées avant la modification de uniqueInstance, empêchant la situation de réorganisation décrite ci-dessus.

55
dasblinkenlight

Pour éviter d'utiliser un double verrouillage, ou volatile j'utilise ce qui suit

enum Singleton {
     INSTANCE;
}

La création de l'instance est simple, chargée paresseusement et sûre pour les threads.

11
Peter Lawrey

L'écriture dans un champ volatile se produira avant toute opération de lecture. Voici un exemple de code pour une meilleure compréhension:

private static volatile ResourceService resourceInstance;
//lazy Initialiaztion
public static ResourceService getInstance () {
    if (resourceInstance == null) { // first check
        synchronized(ResourceService.class) {
            if (resourceInstance == null) { // double check
                // creating instance of ResourceService for only one time
                resourceInstance = new ResourceService ();                    
            }
        }
    }
    return resourceInstance;
}

Ce lien peut mieux vous servir http://javarevisited.blogspot.com/2011/06/volatile-keyword-Java-example-tutorial.html

0
RajeeV VenkaT