当前位置:网站首页>Singleton mode

Singleton mode

2021-08-08 01:10:11 Acelin_ H

Design patterns are divided into creation patterns 、 Structural and behavioral patterns . This article explains the singleton pattern , Create a schema for .


characteristic


Singleton mode has the following characteristics :

  • 1、 A singleton class can have only one instance .
  • 2、 The singleton class must create its own unique instance .
  • 3、 The singleton class must provide this instance to all other objects .

From the above characteristics, we can know

The statement of creating a class in a singleton class must be shielded from the outside world . The characteristic is : Constructor is private

When creating a singleton class , To ensure that there is only one instance of this class , And provide a global access point to access it

Let's see how to implement the above features in different ways .


Realization


The first thing to emphasize is : Divided by the instantiation time of the singleton class , In fact, there are only two modes to implement the singleton mode —— Lazy man mode and hungry man mode . But because the ordinary lazy man model and the hungry man model have more or less disadvantages . So a lot of seed patterns have been derived . So let's see .


One 、 The sluggard model


The lazy man model is different from the hungry man model . Not prepared in advance , Don't instantiate until you need it , It feels lazy . So it's called lazy mode . And the hungry man to be mentioned later , It has been instantiated without using , Very hungry .

public class LazySingleton {

    private volatile static LazySingleton INSTANCE; // volatile Prohibit command rearrangement 

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if (INSTANCE == null){
            INSTANCE = new LazySingleton();
        }
        return INSTANCE;
    }
}

The lazy mode above can only be used in a single thread , In other words, it is non thread safe . It can be seen from the code of ordinary lazy mode above , In the case of multithreading , Instance creation statements may be executed multiple times . So to implement thread safe lazy mode , The simplest way is to add synchronized Keyword modification . as follows :

You can refer to this article , Brush up on synchronized Related knowledge

public class LazySingleton {

    private volatile static LazySingleton INSTANCE; // volatile Prohibit command rearrangement 

    private LazySingleton(){}

    public static synchronized LazySingleton getInstance(){
        if (INSTANCE == null){
            INSTANCE = new LazySingleton();
        }
        return INSTANCE;
    }
}

In the simplest and most brutal way , You can really achieve thread safety Of 0 Of , But familiar synchronize Students believe that they know that the performance of this method is poor . A more efficient implementation will be introduced later —— Double check lock mode


Two 、 Starving model


Compared to the lazy model “ Delay loading ”, Hungry man mode is to generate a unique instance directly when the class is loaded . Such as the following generation of code implementation :

public class HungrySingleton {

    private static HungrySingleton INSTANCE = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getINSTANCE() {
        return INSTANCE;
    }
}

3、 ... and 、 The difference between lazy man mode and hungry man mode


Carefully taste the implementation code of lazy mode and hungry mode , Let's look at the difference between the two :

  • 1、 The sluggard model , Wait until you want to use it before you create an instance , It takes time , But save space , Typical time for space .

  • 2、 Starving model , Whether you use it or not , The only instances of this class are already in jvm The class is instantiated when it is loaded .

    In fact, it is to allocate memory during the connection process of the class and trigger the instantiation of the class , Introduction to the life cycle of classes , You can refer to another article Java Class life cycle analysis

  • 3、 Lazy mode needs to solve thread safety problems . The hungry man model does not need . because jvm When loading classes, it is single threaded . A single instance can be guaranteed .


Four 、 Double check lock


Double check lock is an extension of lazy mode , That is to say, the instantiation of an object is delayed , It is to solve the inefficiency of the common thread safe lazy mode mentioned above .

This way , In fact, it is also synchronized Keyword lock . But there are two layers of verification , Therefore, it is named double check lock .

Let's look at the specific code implementation

public class DoubleCheckSingleton {

    private static volatile DoubleCheckSingleton INSTANCE;

    private DoubleCheckSingleton(){}

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

Next, let's discuss this method relative to synchronized What is the difference between thread safety implemented by locking methods .

  • First we need to know , The purpose of locking the instantiation process , Is that when the singleton has not been generated , Prevent multiple threads from generating multiple instances . That's when we want to lock in , In fact, when no instance is generated . But if you lock the whole method , Will cause you to generate instances , In the future, every time you want to get an instance , Will be affected by the lock . That's not what we want . So , We need to lock it before , First add a layer of verification , To prevent this from happening .
  • As for someone who will ask , Why is there a need for more testing , In fact, it is easy to draw a conclusion through the analysis of : No, Gary , There is no guarantee that the conclusion of a single case . Because multiple threads will pass the first layer verification , If you don't check again , There may be multiple instances

In conclusion , The purpose of the two verifications is different , The first layer of verification is to disable the locking mechanism after a single instance is generated , Avoid unnecessary expenses . Second level verification , This is to ensure the existence of unique instances and delayed loading .


5、 ... and 、 Static inner class pattern


Above, we have introduced the implementation of lazy man mode and hungry man mode , And the implementation of thread safety in lazy mode . From which we can see , Lazy mode , If you can solve thread safety , The implementation timing of singleton is reasonable ; The hungry man mode has the advantage of creating natural thread safety instances , Is there a way to achieve the best of both? ? That is the way to implement the static inner class .

About java Knowledge of inner classes , You can refer to this article :Java Inner class

Let's look at the code implementation :

public class StaticInnerClassSingleton {

    private static class SingletonInnerClass{
        private static StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }

    private StaticInnerClassSingleton(){}

    public static StaticInnerClassSingleton getInstance(){
        return SingletonInnerClass.INSTANCE;
    }
}

The static inner class is used to realize , Can reach one or two points :

1、 When the external class is loaded, the internal class will not be loaded , Only when calling getInstance() Only when the method is , That is, it is loaded only when the is used , This is consistent with the lazy model .

2、 When the inner class is loaded , The instantiation of this singleton class is thread safe , This is consistent with the hungry man model .


6、 ... and 、 Enumeration class


The double check in the hungry and lazy 、 Static inner classes cannot avoid being deserialized and reflected to generate multiple instances . The singleton mode implemented by enumeration can not only avoid the problem of multi-threaded synchronization , It also prevents deserialization and reflection corruption .

A deeper argument , May refer to You know what? ? Enumeration singleton mode is the best singleton mode in the world !!! One article .

And about deserialization breaking singleton features , Previous articles on serialization Java serialize It is also mentioned that , Step by step reading

public enum EnumSingleton {
    INSTANCE;
}

Enumeration singleton mode has the following three advantages :

  • The writing is concise , The code is short and compact .
  • Thread safety .
  • Prevent deserialization and reflection corruption .

版权声明
本文为[Acelin_ H]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/08/20210808010828752l.html

随机推荐