Maison >Java >javaDidacticiel >Quelles sont les différences entre les modèles java singleton ?

Quelles sont les différences entre les modèles java singleton ?

coldplay.xixi
coldplay.xixioriginal
2020-08-17 14:03:161799parcourir

La différence entre le mode Java singleton est la suivante : 1. Une fois la classe Hungry Man chargée, l'initialisation du singleton est terminée, tandis que le Lazy Man ne revient que pour l'initialiser lors de l'appel de getInstance. ; 2. Le style affamé est intrinsèquement thread-safe, tandis que le style paresseux lui-même n'est pas thread-safe.

Quelles sont les différences entre les modèles java singleton ?

[Recommandations d'apprentissage associées : Tutoriel de base Java]

Différences en mode java singleton Oui :

1. Lazy Singleton

//懒汉式单例类.在第一次调用的时候实例化自己   
public class Singleton {  
    private Singleton() {}  
    private static Singleton single=null;  
    //静态工厂方法   
    public static Singleton getInstance() {  
         if (single == null) {    
             single = new Singleton();  
         }    
        return single;  
    }  
}

Singleton évite l'accès externe à la classe en limitant le constructeur à l'instanciation privée, dans le cadre de la même machine virtuelle, la seule instance de Singleton n'est accessible que via la méthode getInstance().

(En fait, grâce au mécanisme de réflexion Java, il est possible d'instancier une classe avec un constructeur privé, ce qui invalidera fondamentalement toutes les implémentations Java singleton. Ce problème ne sera pas abordé ici, alors cachons-le pour pour le moment. On pense que le mécanisme de réflexion n'existe pas. )

Cependant, l'implémentation ci-dessus du singleton paresseux ne prend pas en compte les problèmes de sécurité des threads. Plusieurs instances de Singleton sont susceptibles d'apparaître. un environnement simultané.Pour assurer la sécurité des threads, il existe les trois méthodes suivantes, qui modifient toutes la méthode getInstance pour garantir la sécurité des threads des singletons de style paresseux si vous êtes exposé au mode singleton pour la première fois et que vous ne le faites pas. Si vous en savez beaucoup sur la sécurité des threads, vous pouvez d'abord ignorer les trois étapes suivantes, jeter un œil au singleton de style Hungry, puis revenir en arrière et examiner les problèmes de sécurité des threads après l'avoir lu :

1. Ajoutez la synchronisation à la méthode getInstance

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

2 Vérifiez le verrouillage

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

3. Classe interne statique

public class Singleton {    
    private static class LazyHolder {    
       private static final Singleton INSTANCE = new Singleton();    
    }    
    private Singleton (){}    
    public static final Singleton getInstance() {    
       return LazyHolder.INSTANCE;    
    }    
}

C'est mieux que les 1 et 2 ci-dessus. Cela assure non seulement la sécurité des threads, mais évite également l'impact sur les performances. provoquée par la synchronisation.

2. Hungry-Chinese Singleton

//饿汉式单例类.在类初始化时,已经自行实例化   
public class Singleton1 {  
    private Singleton1() {}  
    private static final Singleton1 single = new Singleton1();  
    //静态工厂方法   
    public static Singleton1 getInstance() {  
        return single;  
    }  
}

Hungry-Chinese Style a déjà créé un objet statique pour une utilisation par le système lors de la création de la classe et ne le modifiera pas dans l'avenir. , il est donc intrinsèquement thread-safe.

3. Singleton enregistré (peut être ignoré)

//类似Spring里面的方法,将类名注册,下次从里面直接获取。  
public class Singleton3 {  
    private static Map<String,Singleton3> map = new HashMap<String,Singleton3>();  
    static{  
        Singleton3 single = new Singleton3();  
        map.put(single.getClass().getName(), single);  
    }  
    //保护的默认构造子  
    protected Singleton3(){}  
    //静态工厂方法,返还此类惟一的实例  
    public static Singleton3 getInstance(String name) {  
        if(name == null) {  
            name = Singleton3.class.getName();  
            System.out.println("name == null"+"--->name="+name);  
        }  
        if(map.get(name) == null) {  
            try {  
                map.put(name, (Singleton3) Class.forName(name).newInstance());  
            } catch (InstantiationException e) {  
                e.printStackTrace();  
            } catch (IllegalAccessException e) {  
                e.printStackTrace();  
            } catch (ClassNotFoundException e) {  
                e.printStackTrace();  
            }  
        }  
        return map.get(name);  
    }  
    //一个示意性的商业方法  
    public String about() {      
        return "Hello, I am RegSingleton.";      
    }      
    public static void main(String[] args) {  
        Singleton3 single3 = Singleton3.getInstance(null);  
        System.out.println(single3.about());  
    }  
}

Le singleton enregistré maintient en fait un ensemble d'instances de la classe singleton et stocke ces instances dans In a Map ( carnet d'inscription), pour les instances qui ont été enregistrées, elles sont renvoyées directement depuis la Map. Pour celles qui ne sont pas enregistrées, elles sont d'abord enregistrées puis restituées.

Ici, j'ai marqué le singleton de style enregistrement comme négligeable. D'après ma compréhension, tout d'abord, il est moins utilisé. De plus, l'implémentation interne utilise toujours le singleton de style chinois en raison du bloc de méthode statique. dans celui-ci, son singleton est instancié lorsque la classe est chargée.

4. La différence entre l'homme affamé et l'homme paresseux

En termes de nom, l'homme affamé et l'homme paresseux,

hungry Han signifie qu'une fois la classe chargée, le singleton est initialisé pour garantir que le singleton existe déjà lorsque getInstance est appelé

L'homme paresseux est paresseux et ne revient pour initialiser le singleton que lorsque getInstance est appelé. .

De plus, les deux méthodes suivantes se distinguent des deux points suivants :

1 Sécurité du fil :

Le style chinois affamé est intrinsèquement du fil. -safe , peut être utilisé directement pour le multi-thread sans problème

Le style paresseux lui-même n'est pas thread-safe. Il existe plusieurs façons d'obtenir la sécurité des threads, à savoir 1, 2 et 3 ci-dessus. implémentations Il existe quelques différences dans le chargement des ressources et les performances.

2. Chargement et performances des ressources :

Le style chinois affamé instancie un objet statique lors de la création de la classe. Que ce singleton soit utilisé ou non plus tard, il occupera une certaine quantité de mémoire. , mais en conséquence, la vitesse sera plus rapide lors du premier appel, car ses ressources ont été initialisées,

et le style paresseux, comme son nom l'indique, retardera le chargement jusqu'à la première fois. singleton est utilisé.L'objet sera instancié et initialisé lors du premier appel. S'il y a beaucoup de travail à faire, il y aura un certain retard dans l'exécution, et ce sera alors la même chose que le style chinois affamé.

Quant aux trois implémentations 1, 2 et 3, il existe quelques différences.

La première ajoute la synchronisation à l'appel de méthode. Bien qu'elle soit thread-safe, elle doit être synchronisée à chaque fois. temps. Cela affectera les performances. Après tout, la synchronisation n'est pas requise dans 99% des cas

La deuxième méthode consiste à effectuer deux vérifications nulles dans getInstance pour s'assurer qu'elle n'est effectuée que lorsque le singleton est appelé. la première fois. La synchronisation, qui est également thread-safe et évite la perte de performances de synchronisation à chaque fois

La troisième méthode utilise le mécanisme classloader pour garantir qu'il n'y a qu'un seul thread lors de l'initialisation de l'instance, c'est donc le cas. également thread-safe et n'entraîne pas de perte de performances, j'ai donc généralement tendance à utiliser celui-ci.

Recommandations d'apprentissage associées : Vidéo de programmation

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn