Design of seven single design pattern

    Singleton design pattern GoF23 is one of the most commonly used design patterns, either third-party libraries or almost daily developers can see the shadow of the singleton, singleton design pattern provides a guarantee instance in the case of multi-threaded the uniqueness of the solution, in order to compare the merits of 7 implementations, we have to be evaluated from three angles: thread of safety, performance, lazy loading.

Hungry Chinese-style

package SingletonPkg;

/**
 * @author Heian
 * @time 19/01/21 12:49
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:饿汉式单例设计模式
 */
public final class Singleton {

    private byte[] data = new byte[1024];//实例变量

    private static Singleton instance = new Singleton ();

    private Singleton(){
        //私有化构造防止外部类new
    }
    public static Singleton getInstance(){
        return instance;
    }
}

    The key is that the hungry man style as a class instance variables and directly initialized (as long as you call this Singleton class, then it will certainly be initialized, initializes Singleton will certainly lead to initialize instance variables (initialization structure will not necessarily go CAUTION), assuming that there is not a class instance variables of the class will not get initialized and the class is final modified as such can not be rewritten, because the initialization subclass will lead to initialize the parent class), then examples instance is created, which includes instance variables are obtained (in the third stage loading class) initialization, such as spatial 1k are simultaneously created, as a class instance variable will be collected into the class initialization procedure in the <clinit> ( ) method, which can ensure synchronization, in the case of multi-threading will only be instantiated once, but after being loaded classloader instance possible to use a very long time, it means that instance instance Embassy will open up the heap memory stay even longer.

    To sum up is less a class property, occupy much memory resources, hungry Chinese-style way not a bad idea, on the contrary, if a class members are relatively heavy resources, it would be this way there is something wrong, such as a singleton category belongs consuming operations. And this model can not be lazy loaded.

Lazy style

package SingletonPkg;

/**
 * @author Heian
 * @time 19/01/21 12:49
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:懒汉式单例设计模式
 */
public final class Singleton2 {

    private byte[] data = new byte[1024];//实例变量

    private static Singleton2 instance = null;//定义实际变量,但不直接初始化

    private Singleton2(){
        //私有化构造防止外部类new
    }
    public static Singleton2 getInstance(){
        if(null == instance){
            instance = new Singleton2 ();
        }
        return instance;
    }
}

    When Singleton2.class initialized instance will not be instantiated in the getInstance method will determine whether the instance has been instantiated, it seems no problem but in a multithreaded environment will result in instance will be instantiated once above, we can not guarantee the uniqueness of the singleton. Since instance a static class variable is modified, i.e. the loading process will be stored in the method area which assumed that the detected thread creates a new instance is null for instance, but since the switch cpu time slice (and therefore most of the data are inconsistent) leads to It was thread 2, at a time when the thread 1 will not create a good instance instance flushed to main memory (not guarantee visibility), so that the thread 2 is created again.

                       

Formula synchronization method lazy +

Lazy man's way can guarantee lazy load an instance, but can not guarantee the uniqueness of instances, the program slightly modified (increased synchronization constraints)

package SingletonPkg;

/**
 * @author Heian
 * @time 19/01/21 12:49
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:懒汉式+同步  单例设计模式
 */
public final class Singleton3 {

    private byte[] data = new byte[1024];//实例变量

    private static Singleton3 instance = null;//定义实际变量,但不直接初始化

    private Singleton3(){
        //私有化构造防止外部类new
    }
    //加入同步控制,同一时刻只有一个线程进入
    public static synchronized Singleton3 getInstance(){
        if(null == instance){
            instance = new Singleton3 ();
        }
        return instance;
    }
}

Using lazy man + synchronization mechanism not only meet the uniqueness of the instance instance, but also meets the lazy loading, but because syncronized keyword natural exclusivity led getInstance method can only be one thread to access the same time, poor performance.

Double-Check

This design pattern is smarter, providing an efficient synchronization strategy, and that is locked when first initialized, after allowing multiple threads to enter the getInstance method to get the instance of the class

package SingletonPkg;

import java.net.Socket;

/**
 * @author Heian
 * @time 19/01/21 12:49
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:Volatile + Double-check  单例设计模式
 */
public final class Singleton5 {

    private byte[] data = new byte[1024];//实例变量

    private static volatile Singleton5 instance = null;//定义实际变量,但不直接初始化

    private Singleton5(){
        //私有化构造防止外部类new
    }
    //加入同步控制,同一时刻只有一个线程进入
    public static Singleton5 getInstance(){
        if(null == instance){
            synchronized (Singleton5.class){
                if (null == instance){
                    instance = new Singleton5 ();
                }
            }
        }
        return instance;
    }
}

In the case of the above-described multi-threaded program, a plurality of threads into the getInstance () method, but the class instance variable is not assigned at this time, only one thread to enter the synchronized code block, for instance a complete instantiation, then there is no need for instance the synchronization protection class variables. This approach seems not only meet the lazy loading ensures the uniqueness of the instance of example, but also to avoid the defect syncronized exclusive, but still there is a problem (instruction reordering). Reordering the instruction command in order to optimize and improve the process efficiency. Reordering instruction including compiled discouraged sorting and reordering operation. JVM specification, instructions may be reordered without affecting the result of single-threaded program execution prerequisite. Example, instance = new Singleton () can be decomposed into the following pseudo-code:

memory = allocate();   //1:分配对象的内存空间
ctorInstance(memory);  //2:初始化对象
instance = memory;     //3:设置instance指向刚分配的内存地址

But after reordering follows:

memory = allocate();   //1:分配对象的内存空间
instance = memory;     //3:设置instance指向刚分配的内存地址                       
ctorInstance(memory);  //2:初始化对象

The Step 2 and Step 3 reverse the order does not affect the results of the program executed in the single-threaded case, but in a multithreaded situation is different. A thread of execution instance = memory (which is visible for another thread B), when the outer thread B executed if (instance == null), found instance is not empty, then returned, but it is obtained not fully initialized instance, when in use must be at risk, which is double-checked locking problem lies!
--------------------- 
Author: zhangzeyuaaa 
Source: CSDN 
Original: https: //blog.csdn.net/zhangzeyuaaa/article/details/42673245 
Disclaimer: This article as a blogger original article, reproduced, please attach Bowen link!

Volatile + Double-Check

    Double-check though is a clever programming, but is likely to lead to instantiate the class member variables occurred after instance, all this is due to the JVM run-time instruction reordering cause, and it is easy to think of the volatile keyword can preventing occurrence instruction reordering, the following

    private static volatile Singleton4 instance = null; // instantiate instance always occurs prior to socket

Holder way

    Holder manner completely by the class loading mechanism, as follows
 

package SingletonPkg;

/**
 * @author Heian
 * @time 19/01/21 12:49
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:Holder  单例设计模式
 */
public final class Singleton6 {

    private byte[] data = new byte[1024];//实例变量

    private static class Holder{
        private static Singleton6 instance = new Singleton6 ();//静态内部类持有singleton的实例,并且可被直接初始化
    }

    private Singleton6(){
        //私有化构造防止外部类new
    }

    public static Singleton6 getInstance(){
        return Holder.instance;
    }
}

    In no instance Singleton classes and static members, but to put it into a static inner classes Holder, so Singleton class initialization process does not cause class initialization Holder, Holder class defines Singleton static variable, and direct initialization, is actively used when Holder Singleton instance is created, the created collected Singleton instance java program to compile time <clinit> () method, which is the synchronization method, the synchronization method can ensure visibility of memory, the JVM instruction order and atomicity. Holder singleton design pattern is one of the best embodiment of the design.

Enumerating

    This approach is "effective java" highly recommended author, enumerating allowed to be inherited, but is thread-safe, and can only be instantiated once, but enumerated types can not be lazy loading, for Singleton actively used, such as static call them the method of the instance will be immediately instantiated.

package SingletonPkg;

import sun.dc.pr.PRError;

/**
 * @author Heian
 * @time 19/01/21 12:49
 * @copyright(C) 2019 深圳市北辰德科技股份有限公司
 * 用途:枚举方式  单例设计模式
 */
public  enum  Singleton7 {//枚举类不允许多继承,已经继承了Enum类
    INSTANCE;
    private byte[] data = new byte[1024];
    Singleton7(){
        System.out.println ("实例化");//默认私有private
    }
    public static void method(){
        //调用该方法也会主动使用Singleton
    }
    public static Singleton7 getInstance(){
        return INSTANCE;
    }

}

 

Guess you like

Origin blog.csdn.net/qq_40826106/article/details/86572460