Le motif singleton paresseux de peu profond à profond

1. La version la plus basique ne tient pas compte des problèmes de sécurité des threads

package JavaBasis.chapter8;

public class Singleton {
    
    
    private static Singleton instance=null;
    private Singleton(){
    
    }//私有化构造函数,外部不可见
    private static Singleton getInstance()
    {
    
    
           if(instance==null)//实例未被创建
           instance=new Singleton();

           return instance;//返回创建的实例
    }
}

2. L'introduction de problèmes multithreads

Le code ci-dessus présente des problèmes d'insécurité de thread dans un environnement multithread. Par exemple, le thread 1 s'exécute d'abord sur l'instruction de jugement if et constate que l'instance n'a pas été créée, il commence donc à créer l'instance; à ce stade, le thread 2 arrive encore une fois, mais l'instance du thread 1 ne l'a pas encore Après la création, le jugement if est toujours satisfait, puis le thread 2 entre dans l'instruction de création, ce qui entraîne deux objets instace à la fin

  • Solution 1 Ajouter un verrou à l'ensemble de la méthode
package JavaBasis.chapter8;

public class Singleton {
    
    
    private static Singleton instance=null;
    private Singleton(){
    
    }//私有化构造函数,外部不可见
    private static synchronized Singleton getInstance()
    {
    
    
           if(instance==null)//实例未被创建
           instance=new Singleton();

           return instance;//返回创建的实例
    }
}

Cette solution peut résoudre le problème de sécurité des threads, mais il y a un autre problème. Étant donné que toute la méthode est verrouillée, supposons que j'ai maintenant un thread 1 qui obtient le verrou et entre la méthode pour créer l'objet. Le thread 1 se termine, puis Thread 2 vient et la méthode trouve que l'objet a été créé et retourne directement, mais si le thread 3 arrive également à ce moment, parce que toute la méthode est verrouillée, le thread 3 ne peut pas entrer. Il doit attendre que le thread 2 se termine avant de pouvoir entrer, mais il souhaite simplement renvoyer un objet qui a été créé, perdant du temps et entraînant une surcharge de performances, et vous pouvez alors proposer la solution suivante

  • Solution 2 Ajouter synchronisé au processus de création
package JavaBasis.chapter8;

public class Singleton {
    
    
    private static Singleton instance=null;
    private Singleton(){
    
    }//私有化构造函数,外部不可见
    private  static  Singleton getInstance()
    {
    
           if(instance==null)//实例未被创建
           {
    
    
           synchronized(Singleton.class)
           {
    
     instance=new Singleton();
           }
           }

           return instance;//返回创建的实例
    }
}

Le code ci-dessus présente également des problèmes de sécurité des threads. Le thread 1 entre en premier dans la méthode et obtient le verrou pour commencer à créer l'objet. Avant la création de l'objet thread 1, le thread 2 entre également en jeu. Le thread 2 détermine s'il trouve que l'objet a n'a pas été créé, donc Enter, mais ne peut pas obtenir le verrou, il commence donc à attendre. Une fois que le thread 1 a créé l'objet et libéré le verrou, le thread 2 crée à nouveau l'objet, car il a déjà effectué un jugement if avant

  • Solution 3 Double verrouillage d'inspection
package JavaBasis.chapter8;

public class Singleton {
    
    
    private static Singleton instance=null;
    private Singleton(){
    
    }//私有化构造函数,外部不可见
    private  static  Singleton getInstance()
    {
    
           if(instance==null)//实例未被创建
           {
    
    
           synchronized(Singleton.class)
           {
    
     
           if(instance==null)
           instance=new Singleton();
           }
           }

           return instance;//返回创建的实例
    }
}

Le problème ci-dessus peut être résolu en ajoutant un jugement au problème du schéma 2, tel que le thread 2 mentionné dans le schéma 2, bien qu'il ait passé le premier jugement if, quand il obtient le verrou, il effectuera le jugement if. on constate que l'objet a été créé par le thread 1, donc il est directement renvoyé à l'objet, jusqu'à présent, pensez-vous que vous avez terminé, mais même s'il s'agit d'un verrou de double vérification, il y a certains problèmes

      if(instance==null)//实例未被创建
           {
    
    
           synchronized(Singleton.class)
           {
    
     
           if(instance==null)
           instance=new Singleton();//1
           }
           }

En regardant ce code, le processus de création d'un objet est divisé en trois étapes suivantes:
1. Allouer l'espace mémoire de l'
objet 2. Initialiser l'objet
3. Laisser l'instance point de référence sur l'adresse de l'objet initialisé,
mais l'instruction le réarrangement se produit en Java Plus précisément, l'ordre de 2 et 3 sera changé. Il peut exécuter 3 puis exécuter 2. Quels problèmes cela causera-t-il?
Par exemple: le thread 1 entre dans le bloc de code synchronisé et commence à créer des objets, exécute 1, puis exécute 3. Une fois que l'exécution de 3instance n'est pas nulle, l'instance pointe vers une adresse claire, mais l'objet de cette adresse n'est pas initialisé. Lorsque le thread 1 n'a pas eu le temps d'effectuer l'opération 2, le thread 2 entre et il trouve la première instruction if (ou peut-être la deuxième instruction if). L'instance à l'intérieur n'est pas nulle, donc l'instance est
renvoyée directement, mais l'instance est un objet non initialisé. Solution: ajoutez le mot-clé volitile devant l'instance, et le le réarrangement des instructions sera fermé.

Je suppose que tu aimes

Origine blog.csdn.net/qq_43478694/article/details/114966158
conseillé
Classement