当前位置:网站首页>Hard core analysis lazy single case

Hard core analysis lazy single case

2022-06-11 15:22:00 Evader1997

   This article focuses on the lazy singleton pattern , Mainly about thread safety .

   All the partners who have seen my singleton mode know , The definition of the actual singleton pattern is simple , There is a private nonparametric construct , And providing a method for obtaining singletons . The simplest way to do this is :

public class LazySingeton {
    
    private static LazySingeton singeton;

    private LazySingeton() {
    

    }

    public LazySingeton getSingeton() {
    
        if (singeton == null) {
    
            singeton = new LazySingeton();
        }
        return singeton;
    }
}

   This code has no problem in the case of single thread , But in Thread safety should be considered in multithreaded environment . An inappropriate example , But the impression must be deep , There is only one pit in the bathroom of the boys' dormitory ,A I didn't lock the door when I entered the bathroom , This is the time B The stomach ache pushes the door directly , Immediately take off your pants and squat down . What happens later will be compensated by the brain , In short, there must be a problem ,A The pit has not been used up yet ,B Just came in , This is not a strong man , Male plus male ? The probability of such a thing happening is relatively small . therefore The solution to this problem is A Lock the bathroom door after entering the bathroom .

   As it happens ,Java There is a lock in the , Lock first , Just like this. :

public class LazySingeton {
    
    private static LazySingeton singeton;

    private LazySingeton() {
    

    }
	
	//  add to synchronized lock , Ensure that the method to get the singleton is called in only one place 
    public synchronized LazySingeton getSingeton() {
    
        if (singeton == null) {
    
            singeton = new LazySingeton();
        }
        return singeton;
    }
}

   adopt synchronized Keywords can guarantee thread safety , But the current writing method can be optimized , How to optimize it ? Or the example of going to the bathroom , Some bathroom doors have a prompt function , Closing the door shows someone , Opening the door shows no one . The big guy at the clock door knows whether there is anyone inside , If it is a door without prompt function , The normal operation is knocking on the door , Ask if anyone .

   The above code is the operation of knocking on the door , This is more performance consuming , Every request needs to be judged getSingeton() Whether the method is locked , It's like a buddy squatting in the pit , No one came in and knocked on the door , hi , Is there anyone inside ?

   So we should add a prompt function , See if there is anyone in the bathroom ? Corresponding to the code is the single instance singeton Judge , Is it null. If null No more initialization ( Don't ask if there is anyone in the pit ), Go straight back to ( Straight away ). Is this method very efficient , The code is as follows :

public class LazySingeton {
    
    private static LazySingeton singeton;

    private LazySingeton() {
    

    }

    public LazySingeton getSingeton() {
    
        //  Judge whether the single case is null, Not for null Just go back ( Reduce the performance consumption of determining whether to lock each time )
        if (singeton == null) {
    
            synchronized(LazySingeton.class){
    
                singeton = new LazySingeton();
            }
        }
        return singeton;
    }
}

   After reading this version of code, students with big brain holes will have this question , In this way, it is not necessary to judge whether to lock ? Thinking is right , here ** Locking is inevitable , To ensure thread safety , Knock on the door is sure to knock , But is reducing the number of knocks equal to improving performance ?** Only in singeton by null Will judge whether it is locked , If singeton Not for null, This saves the cost of code execution in the synchronization block .

   There are still problems in the code , This problem will be clear from the picture :
 Insert picture description here
   The reason for this problem is that thread one has not new, Thread 2 passes if(singeton = null) The judgment of the , Sneak into the later process , It's like a person who hasn't locked the bathroom yet , Another man rushed in . It's easy to solve this problem , Since you skipped if(singeton = null) The judgment of the , So I'm judging for once !, In this way, even if thread 2 narrowly escaped the first round of verification , I can't escape the second round , This ensures that only one object is created . The specific code is as follows :

public class LazySingeton {
    
    private static LazySingeton singeton;

    private LazySingeton() {
    

    }

    public LazySingeton getSingeton() {
    
        //  For the first time 
        if (singeton == null) {
    
            synchronized (LazySingeton.class) {
    
                //  Second judgment 
                if (singeton == null) {
    
                    singeton = new LazySingeton();
                }
            }
        }
        return singeton;
    }
}

   Is there any problem with the above contents ? The answer is yes , Next comes to JVM Related knowledge : Instruction reordering . The following content can be understood by beginners , You don't have to dig deep for the first time . First of all, let's look at the following figure , have a look singeton = new LazySingeton(); This line of code is in JVM How is it implemented .
 Insert picture description here
   This process should be clear to everyone , Now suppose A,B Two threads get the singleton at the same time ,A Thread enters synchronization block , After performing the above operations , Direct release lock . At this time, other threads will enter the synchronized code block , At this point, if the thread A Just opened up space in memory , Instead of instantiating this Empty shell , Then the second thread goes to if when , I won't go if Code inside . So the result is null. The words are a little difficult to understand , Let's look at the pictures .
 Insert picture description here
The final code is as follows :

public class LazySingeton {
    
    //  increase volatile Modifier , Prevent instruction reordering 
    private volatile static LazySingeton singeton;

    private LazySingeton() {
    

    }

    public LazySingeton getSingeton() {
    
        if (singeton == null) {
    
            synchronized (LazySingeton.class) {
    
                if (singeton == null) {
    
                    singeton = new LazySingeton();
                }
            }
        }
        return singeton;
    }
}

Extracurricular knowledge , If you are interested, you can study instruction reordering , This article does not delve into , Provide a picture for everyone to understand :
 Insert picture description here

原网站

版权声明
本文为[Evader1997]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206111518260695.html