Maison  >  Article  >  Java  >  Explication détaillée de la façon d'implémenter les modèles Hungry Man et Lazy Man en mode Java singleton

Explication détaillée de la façon d'implémenter les modèles Hungry Man et Lazy Man en mode Java singleton

PHPz
PHPzavant
2023-04-27 12:40:071402parcourir

Qu'est-ce que le modèle singleton ?

Il garantit qu'une seule instance d'une certaine classe existe dans le programme au lieu de créer plusieurs instances, ce qui améliorera l'efficacité.

En mode d'intérêt unique, généralement une seule méthode getInstance() est fournie pour obtenir l'objet instance, et la méthode setInstance() n'est pas fournie. Le but est d'éviter d'instancier d'autres objets instance.

Il existe deux modes en mode singleton, l'un est le mode affamé et l'autre est le mode paresseux.

1. Mode Han affamé

1. Le concept du mode Han affamé

Mode Han affamé signifie que la classe sera instanciée immédiatement lorsqu'elle sera chargée, et qu'une seule instance apparaîtra lors des utilisations ultérieures.

2. Code du mode affamé
package thread.example;
//饿汉模式
public class HungrySingle {
//在类加载的时候就实例化了,类加载只有一次,所以值实例化出了一份该实例对象
    private static HungrySingle instance = new HungrySingle();
    public static HungrySingle getInstance() {
        return instance;
    }
}
3. Le multi-thread est-il thread-safe ?

Il a déjà été instancié lorsque la classe est chargée, donc l'instanciation n'implique pas l'opération de modification de l'instanciation, seulement l'opération de lecture. . Il est thread-safe dans les situations multithread.

2. Mode paresseux

1. Le concept de mode paresseux

n'est pas instancié directement lorsque la classe est chargée, mais est instancié lorsque la méthode d'instance spécifiée est appelée, afin de garantir qu'elle ne sera pas utilisée lorsque vous je ne veux pas l'utiliser. De manière générale, il est plus efficace que le mode Hungry Man.

2. Mode paresseux dans une situation monothread
package thread.example;
//单线程的懒汉模式
public class LazySingle {
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static LazySingle getInstance() {
        if(instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}
3. Mode paresseux dans une situation multithread

(1) Raisons pour lesquelles le mode paresseux n'est pas sûr dans des situations multithread

Dans des situations multithread, à cause de cela. Il est possible que les deux threads obtiennent une instance = null. En effet, si le thread 1 modifie l'instance dans son propre comté avant d'avoir le temps de modifier l'instance dans la mémoire principale, le thread 2 instanciera également un objet instance à ce moment-là. , ce n'est plus un mode singleton. La cause principale de ce problème est qu'il implique la modification de l'instance et la perte de l'atomicité. Afin de garantir l'atomicité, nous avons pensé au verrouillage pour assurer la sécurité des threads.

(2) Exemple de code de solution

Version 1

package thread.example;
//多线程安全下的懒汉模式
    public class LazySingle {
        private LazySingle() {
    }
    private static LazySingle instance = null;
    //只有在调用该方法的时候才实例化
    public static synchronized LazySingle getInstance() {
        if (instance == null) {
            instance = new LazySingle();
        }
        return instance;
    }
}

Bien que le code de la version 1 garantisse la sécurité des threads, des problèmes de verrouillage et de déverrouillage se produiront toujours à chaque appel de la méthode. Afin d'optimiser davantage, nous pouvons réduire le verrouillage. La granularité est utilisée pour améliorer l'efficacité, car après l'ajout de verrous, une concurrence élevée n'est plus possible, mais nous voulons toujours améliorer l'efficacité, nous l'optimisons donc.

Version 2

Le verrouillage du jugement double if améliore l'efficacité

package thread.example;
 
public class SecurityLazyModle {
    private LazySingle() {
    }
    private static volatile SecurityLazyModle instance = null;//保证内存可见性,防止编译器过度优化(指令重排序)
    public static SecurityLazyModle getInstance() {
        if(instance == null) {
            synchronized (SecurityLazyModle.class) {
                if(instance == null) {
                    instance = new SecurityLazyModle();
                }
            }
        }
        return instance;
    }
}

Explication de la version 2

La première couche de if consiste à déterminer si l'instance a été créée, et la deuxième couche de synchronisation consiste à la faire entrer dans le if actuel Les threads se disputent le verrou. Lorsque le thread qui obtient le verrou entre dans la troisième couche de if, il détermine s'il est vide, il instancie l'objet, puis libère le verrou. l'instance n'est plus vide et les threads suivants sont bloqués au troisième niveau si. Plus tard, lors de l'accès à la méthode getInstance(), on constate que l'instance n'est plus vide, il n'est donc pas nécessaire de saisir la ressource de verrouillage. , car rivaliser pour le verrou prend également beaucoup de temps. En traitant de cette manière, la sécurité des threads est assurée et l'efficacité est améliorée.

Le but de l'utilisation de volatile ici est d'empêcher la réorganisation des instructions causée par l'optimisation du compilateur. L'exécution d'un nouvel objet n'est pas une opération atomique et peut être divisée en trois étapes :

  1. 1. 2. Instanciez l'objet

  2. 3. Attribuez une valeur à la variable

  3. Pour l'exécution ci-dessus, si 1 et 3 sont exécutés en premier (en supposant que 2 n'a pas été terminé), le thread en dehors de la première couche de if ne sera pas nul pour le moment, l'objet sera renvoyé directement à ce moment, mais cet objet n'est qu'à moitié exécuté et son utilisation ultérieure entraînera des problèmes de sécurité des threads.

  4. Volatile peut garantir que ces 3 étapes doivent être exécutées (quel que soit l'ordre, elles seront finalement exécutées) avant que les threads externes puissent s'exécuter. À ce stade, l'intégrité de l'objet est garantie.

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:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer