web-dev-qa-db-fra.com

Thrott Safe Singletons in Java

L'article de Wikipédia sur Singletons mentionne quelques façons sûres pour les threads d'implémenter la structure en Java. Pour mes questions, considérons les singletons qui ont de longues procédures d'initialisation et qui sont acccessés par de nombreux threads à la fois.

Tout d'abord, cette méthode non mentionnée est-elle sûre pour les threads, et si oui, sur quoi se synchronise-t-elle?

public class Singleton {
    private Singleton instance;

    private Singleton() {
        //lots of initialization code
    }

    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Deuxièmement, pourquoi le thread d'implémentation suivant est-il sûr ET paresseux lors de l'initialisation? Que se passe-t-il exactement si deux threads entrent en même temps dans la méthode getInstance()?

public class Singleton {
    private Singleton() {
        //lots of initialization code
    }

    private static class SingletonHolder { 
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

Enfin, dans le deuxième exemple, que se passe-t-il si un thread obtient d'abord une instance et qu'un autre thread obtient une instance et essaie d'exécuter des actions dessus avant que le constructeur n'ait terminé dans le premier thread? Pouvez-vous alors entrer dans un état dangereux?

38
donnyton

Réponse 1: Les méthodes static synchronized Utilisent l'objet classe comme verrou - c'est-à-dire dans ce cas Singleton.class.

Réponse 2: Le langage Java, entre autres:

  • charge les classes lors de leur premier accès/utilisation
  • garantit qu'avant l'accès à une classe, tous les initialiseurs statiques sont terminés

Ces deux faits signifient que la classe statique interne SingletonHolder n'est pas chargée tant que la méthode getInstance () n'est pas appelée. À ce moment, et avant que le thread effectuant l'appel n'y ait accès, l'instance statique de cette classe est instanciée dans le cadre du chargement de la classe.

Tout cela signifie que nous avons un chargement paresseux sûr, et sans n'importe quoi besoin de synchronisation/verrous!

Ce modèle est le modèle à utiliser pour les singletons. Il bat les autres modèles parce que MyClass.getInstance() est la norme industrielle de facto pour les singletons - tous ceux qui l'utilisent automatiquement savent qu'ils traitent avec un singleton (avec du code, c'est toujours bon d'être évident), donc ce modèle a le bonne API et la bonne implémentation sous le capot.

btw article de Bill Pugh mérite d'être lu pour être complet lors de la compréhension des motifs singleton.

46
Bohemian