Java design pattern-singleton pattern

Singleton mode

basic introduction

The so-called singleton design pattern of a class is to take a certain method to ensure that in the entire software system, there can only be one object instance for a certain class, and the class only provides a method (static method) to obtain its object instance .

For example, Hibernate's SessionFactory, which acts as a proxy for data storage sources and is responsible for creating Session objects. SessionFactory is not lightweight. Under normal circumstances, only one SessionFactory is required for a project, which will use singleton mode.

There are eight ways in singleton mode:

1) Hungry style (static constant)
2) Hungry style (static code block)
3) Lazy style (thread-unsafe)
4) Lazy style (thread-safe, synchronized method)
5) Lazy style (thread-safe, synchronized code block )
6) Double check
7) Static inner class
8) Enum

Hungry Chinese

Static constant writing

1) The constructor is privatized (to prevent new )
2) The object is created inside the class I
3) A static public method is exposed to the outside

Code

/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 15:59
 * @Description TODO
 * @pojectname 饿汉式(静态变量写法)
 */
public class SingletonTest01 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1);
        System.out.println("instance的hashcode"+instance.hashCode());
        System.out.println("instance1的hashcode"+instance1.hashCode());
    }
}
class Singleton{
    
    
    //1.构造器私有,让外部不能new
    private Singleton(){
    
    }

    //2.本类内部创建对象实例
    private final static Singleton instance = new Singleton();

    //3.对外提供一个共有的静态方法,返回实例对象
    public static Singleton getInstance(){
    
    
        return instance;
    }
}
true
instance的hashcode1836019240
instance1的hashcode1836019240

It must be the same object, because two calls to getInstance return the same instance object

Pros and cons

**Advantages:** This writing method is relatively simple, that is, the instantiation is completed when the class is loaded. Avoid thread synchronization problems.

Disadvantages:

The instantiation is completed when the class is loaded, and the effect of Lazy Loading is not achieved . If you have never used this example from start to finish, it will cause the waste of memory

This method is based on the classloder mechanism to avoid multi-threaded synchronization problems. However, the instance is instantiated when the class is loaded. In the singleton mode, the getInstance method is mostly called, but there are many reasons for the class loading, so it cannot Make sure that there are other ways (or other static methods) that cause the class to be loaded. At this time, initializing the instance does not achieve the effect of lazy loading

Static code block writing

Code

/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 15:59
 * @Description TODO
 * @pojectname 饿汉式(静态代码块写法)
 */
public class SingletonTest01 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1);
        System.out.println("instance的hashcode"+instance.hashCode());
        System.out.println("instance1的hashcode"+instance1.hashCode());
    }
}

class Singleton{
    
    
    //1.构造器私有,让外部不能new
    private Singleton(){
    
     }

    //2.本类内部创建对象实例
    private static Singleton instance;

    static {
    
    
        //在静态代码块中创建单例对象
        instance = new Singleton();
    }
    //3.对外提供一个共有的静态方法,返回实例对象
    public static Singleton getInstance(){
    
    
        return instance;
    }
}

This method is similar to the above method, except that the process of class instantiation is placed in a static code block. When the class is loaded , the code in the static code block is executed to initialize the instance of the class. The advantages and disadvantages are the same as above.
Conclusion: This singleton mode is available, but it may cause a waste of memory

Lazy man

Thread unsafe

Code

/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 16:17
 * @Description TODO
 * @pojectname 线程不安全的懒汉式写法
 */
public class SingletonTest03 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1);
        System.out.println("instance的hashcode"+instance.hashCode());
        System.out.println("instance1的hashcode"+instance1.hashCode());
    }
}
class Singleton{
    
    
    private static Singleton instance;
    //私有化构造方法
    private Singleton(){
    
    }
    //提供一个静态的公有方法,当时用到该方法时,才去创建instance
    public static Singleton getInstance(){
    
    
        if (instance == null){
    
    
            instance = new Singleton();
        }
        return instance;
    }
}

Pros and cons

It has the effect of Lazy Loading , but it can only be used in a single thread.
If under multi-threading, one thread enters the if (singleton == null) judgment statement block, and there is no time to execute it in the future, and another thread also passes the judgment statement, then multiple instances will be generated. Therefore, this method cannot be used in a multi-threaded environment

Conclusion: In actual development, do not use this method.

Synchronization method

The above unsafe writing problem tells us that the main problem is that when getInstance, there will be multi-line super, and entering at the same time will cause insecurity, then we will find a way to deal with it and make this method safe

Code

package com.wang.singleton.type4;
/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 16:17
 * @Description TODO
 * @pojectname 线程安全的懒汉式写法
 */
public class SingletonTest03 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1);
        System.out.println("instance的hashcode"+instance.hashCode());
        System.out.println("instance1的hashcode"+instance1.hashCode());
    }
}
class Singleton{
    
    
    private static Singleton instance;
    //私有化构造方法
    private Singleton(){
    
    }
    //提供一个静态的公有方法,当时用到该方法时,才去创建instance
    //使用synchronized关键字 同步处理代码,解决线程安全问题
    public static synchronized Singleton getInstance(){
    
    
        if (instance == null){
    
    
            instance = new Singleton();
        }
        return instance;
    }
}

Pros and cons

Solve the problem of thread insecurity

The efficiency is too low . When each thread wants to obtain an instance of the class, the execution of the getInstance() method must be synchronized. In fact, this method is enough to execute the instantiation code only once. If you want to obtain an instance of this class later, just return directly. The method is too inefficient for synchronization.
Conclusion: In actual development, this method is not recommended

Synchronization code block

The above synchronization method is inefficient, so how can we solve this inefficient problem?

Code

package com.wang.singleton.type5;
/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 16:17
 * @Description TODO
 * @pojectname 线程安全的懒汉式写法(同步代码块)
 */
public class SingletonTest03 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1);
        System.out.println("instance的hashcode"+instance.hashCode());
        System.out.println("instance1的hashcode"+instance1.hashCode());
    }
}
class Singleton{
    
    
    private static Singleton instance;
    //私有化构造方法
    private Singleton(){
    
    }
    //提供一个静态的公有方法,当时用到该方法时,才去创建instance
    //使用synchronized关键字 同步处理代码,解决线程安全问题
    public static  Singleton getInstance(){
    
    
        if (instance == null){
    
    
            synchronized (Singleton.class) {
    
    
                instance = new Singleton();
            }
        }
        return instance;
    }
}

Pros and cons

In this way, the original intention is to improve the fourth implementation, because the previous synchronization method is too inefficient, and it is changed to synchronize the instantiated code blocks,
but this synchronization does not play a role in thread synchronization. Consistent with the situation encountered in the third implementation method, if a thread enters the if (singleton == null) judgment statement block, and there is no time to execute it in the future, another thread also passes the judgment statement , then it will be generated Multiple examples
Conclusion: In actual development, this method cannot be used

Singleton mode

Double detection lock mode

Also called DCL lazy man

Code

/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 16:17
 * @Description TODO
 * @pojectname 双重检查写法 DCL
 */
public class SingletonTest03 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance==instance1);
        System.out.println("instance的hashcode"+instance.hashCode());
        System.out.println("instance1的hashcode"+instance1.hashCode());
    }
}

class Singleton{
    
    
    //使用volatile保证对内存的及时可见性
    private static volatile Singleton instance;
    //私有化构造方法
    private Singleton(){
    
    }
    //提供一个静态的公有方法,当时用到该方法时,才去创建instance
    //使用synchronized关键字 同步处理代码,解决线程安全问题
    public static Singleton getInstance(){
    
    
        if (instance == null){
    
    
            synchronized (Singleton.class) {
    
    
                if (instance == null) {
    
    
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Let's analyze it,

If we are now in a multi-threaded environment, there are two more special threads A and B, they have gone to the outer judgment if (instance == null), eh, we know, now AB does not have an instance of this instance , So we have to create it, then AB squeezed in, eh, ran into a wall synchronized (Singleton.class), locked this instance object (about who is the lock, my other blog JUC talks about https:/ /blog.csdn.net/qq_22155255/article/details/109749311), who is ahead of AB, if A goes in first, B is waiting outside ( note, B is null at this time, there is no instance yet ) A goes in I encountered the second judgment that if (instance == null) is satisfied, eh, I came in and created a new instance. At this time, our keyword volatile above works, instance is not empty, and B has an instance, so Do not go through the creation of instance objects in the second level of inspection

Pros and cons

The Double-Check concept is often used in multithreaded development. As shown in the code bug, we have performed two if (singleton==null) checks to ensure thread safety.
In this way, the instantiation code only needs to be executed once, and when it is accessed again later, it is judged if (singleton == null), and the instantiated object is directly returned, which also avoids repeated method synchronization. Thread safety; lazy loading; higher efficiency
Conclusion: in In actual development, it is recommended to use this singleton design pattern

Static inner class

Characteristics of static inner classes

When our Singleton class is loaded, our static inner class will not be loaded. When we need to call the getInstance method to use static variables, the static inner class will be loaded , and it will only be loaded once , And there are no thread safety issues

Code

package com.wang.singleton.type7;
/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 16:17
 * @Description TODO
 * @pojectname 使用静态内部类完成单例模式
 */
public class SingletonTest03 {
    
    
    public static void main(String[] args) {
    
    
        //测试
        Singleton instance2 = Singleton.getInstance();
        Singleton instance3 = Singleton.getInstance();
        System.out.println(instance2==instance3);
        System.out.println("instance的hashcode"+instance2.hashCode());
        System.out.println("instance1的hashcode"+instance3.hashCode());
    }
}
//静态内部类完成
class Singleton{
    
    
    //使用volatile保证对内存的及时可见性
    private static volatile Singleton instance;
    //构造器私有化
    private Singleton(){
    
    }
    //写一个静态内部类,该类中有一个静态属性Singleton
    private static class SingletonIntsance{
    
    
        private static final Singleton INSTSANCE = new Singleton();
    }
    //提供一个静态公有方法,直接返回SingletonIntsance.INSTSANCE
    public static synchronized Singleton getInstance(){
    
    
        return SingletonIntsance.INSTSANCE;
    }
}

Pros and cons

1. When our Singleton class is loaded, our static inner class will not be loaded. When we need to call the getInstance method to use static variables, the static inner class will be loaded to ensure our Lazy loading

2. Using the loading mechanism of the JVM class, it will only be loaded once and instantiated once.

3. The static properties of the class will only be initialized when the class is loaded for the first time , so here, JVM helps us to ensure the safety of the thread . When the class is initialized, other threads cannot enter.

Advantages: avoid thread insecurity, use static internal class characteristics to achieve lazy loading, high efficiency
Conclusion: recommended

Enumeration method

Code

package com.wang.singleton.type8;
/**
 * @author 王庆华
 * @version 1.0
 * @date 2020/12/20 16:59
 * @Description TODO
 * @pojectname 枚举方式
 */
public class SingletonTest08 {
    
    
    public static void main(String[] args) {
    
    
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System.out.println(instance == instance2);
        System.out.println("instance1的"+instance.hashCode());
        System.out.println("instance2的"+instance2.hashCode());
        instance.sayOK();
    }
}
enum Singleton{
    
    
    INSTANCE;//属性只有一个,保证单例
    public void sayOK(){
    
    
        System.out.println("OK~~");
    }
}

Pros and cons

This uses the enumeration added in JDK1.5 to implement the singleton mode. Not only can avoid multi-thread synchronization problems, but also prevent deserialization from re-creating new objects .
This method is the method advocated by Effective Java author Josh Bloch
Conclusion: Recommended

The case and solution of singleton mode being reflected, deserialization destruction is written in my other blog

https://blog.csdn.net/qq_22155255/article/details/109749311 The seventeenth singleton mode is written in detail

Source code

In our JDK, java.lang.Runtime is the classic singleton mode

public class Runtime {
    
    
    private static Runtime currentRuntime = new Runtime();
        /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
    
    
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {
    
    }

It can be seen that Runtime uses our hungry man-style singleton mode to create objects

Notes and details of singleton mode

1) The singleton mode ensures that only one object of this class exists in the system memory, which saves system resources. For some objects that need to be created and destroyed frequently, using the singleton mode can improve system performance.
2) When you want to instantiate a singleton class At that time, you must remember to use the corresponding method of obtaining objects instead of using new
3) **Scenarios used in singleton mode: **Objects that need to be created and destroyed frequently, too much time or cost in creating objects Too many resources (ie: heavyweight objects), but often used objects, tool objects, objects that frequently access databases or files (such as data sources, session factories, etc.)

Guess you like

Origin blog.csdn.net/qq_22155255/article/details/111451717