web-dev-qa-db-fra.com

Singleton paresseuse vs instanciée

Si un singleton est implémenté comme suit,

class Singleton {
    private static Singleton instance = new Singleton();

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

En quoi cette implémentation est-elle différente de l’approche d’initialisation différée? Dans ce cas, l’instance sera créée lorsque la classe est chargée et la classe elle-même n’est chargée que lors de la première utilisation active (par exemple, Singleton.getInstance ( ) pas lorsque vous déclarez par exemple Singleton singleton = null;)

Même avec une approche d'initialisation lente, l'instance est créée sur l'appel de getInstance ()

Est-ce que j'ai râté quelque chose?

22
java_geek

Vous pouvez également appeler toute autre méthode statique ou variable membre statique pour charger l'instance de singleton.

class Logger {     
   private static Logger instance = new Logger(); 
   public static String LOG_LINE_SEPERATOR =  
      System.getProperty("line.separator");
   public static Logger getInstance() {  
          return instance;     
   } 

   public static String logPattern() {
       return null;
   }
} 

...

Logger.LOG_LINE_SEPERATOR; // load Logger instance or
Logger.logPattern(); // load Logger instance
12
Prince John Wesley

Avec une initialisation différée, vous ne créez une instance que lorsque c'est nécessaire et non pas lorsque la classe est chargée. Donc, vous échappez à la création d'objet inutile. Cela étant dit, vous devez également prendre en compte d’autres éléments. Lors d’une initialisation différée, vous attribuez une API publique à l’instance. Dans un environnement multithread, il est difficile d'éviter la création inutile d'objets. vous mettez des blocs de synchronisation qui nécessitent un verrouillage inutile pour vérifier l'objet déjà créé. Cela devient donc un problème de performance dans ce cas. 

Donc, si vous êtes sûr que la création de votre objet ne prendra pas de mémoire significative et que son utilisation sera presque toujours utilisée dans votre application, il est alors bon de la créer en initialisation statique. De plus, n'oubliez pas de rendre votre instance finale dans ce cas, car elle garantit que la création de l'objet est reflétée correctement et intégralement dans la mémoire principale, ce qui est important dans un environnement multithread.

Référez-vous s'il vous plaît à ce tutoriel de IBM sur Singleton + Lazy Loading + Multithreaded Environment case

=============== Modifier le 09/09/2018 ====================

Vous devez également examiner le modèle de création d’objet à la demande ici .

18
Saurabh

Pour les raisons que vous avez mentionnées, c’est une façon plus compliquée de faire la même chose que

enum Singleton {
    INSTANCE;
}

L'utilisation de l'initialisation différée n'est utile que si vous craignez que la classe ne puisse être initialisée mais que vous ne souhaitiez pas charger le singleton à ce stade. Pour la plupart des situations, c'est tuer plus.

Remarque: le simple fait de référencer la classe ne l'initialise pas.

par exemple. Supposons que vous ayez une classe mal écrite qui ne puisse être initiée tant qu'une condition n'est pas définie. Dans ce cas, n doit être différent de zéro.

public class Main {
    public static void main(String ... args) {
        Class c= LazyLoaded.class;
        System.out.println(c);
    }

    static class LazyLoaded {
        static int n = 0;
        static {
            System.out.println("Inverse "+1000/n);
        }
    }
}

empreintes

class Main$LazyLoaded
6
Peter Lawrey

Tout d’abord, le motif singleton est surutilisé. Ce que vous voulez vraiment faire si vous voulez "un de quelque chose" est de le déclarer un singleton dans le cadre de votre choix de DI. Il s’agit bien d’un singleton impatient entraîné par la configuration et libère des options pour l’injection de simulacres permettant de réaliser les tests appropriés. 

Pourquoi pas paresseux? À moins que votre classe ait une routine d'initialisation massive dans la construction (ce qui, à mon avis, est également un anti-motif), il n'y a aucun avantage et beaucoup d'inconvénients au chargement paresseux. Vous ne faites qu'ajouter de la complexité et éventuellement casser votre programme si ce n'est pas fait correctement. La bonne façon (si vous devez) est d'utiliser l'idiome de titulaire Initialization-on-Demand. 

0
Travis

Pour l'instance singleton de chargement paresseux, j'utilise comme ci-dessous.

class Singleton {
private static Singleton instance;
private Singleton(){

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