23 design patterns-singleton pattern [hungry style, lazy style, double check, static inner class, enumeration]

Series of articles

23 design patterns-the purpose of design patterns and the seven principles to follow
23 design patterns-singleton mode [hungry, lazy, double check, static internal classes, enumeration]
23 design patterns-factory mode [Simple factory, factory method, abstract factory]
23 design modes-prototype mode [clone sheep, shallow copy, deep copy]


Design pattern type

1. Creation mode: singleton mode, abstract factory mode, prototype mode, builder mode, factory mode;

2. Structural mode: adapter mode, bridge mode, decoration mode, combination mode, appearance mode, flyweight mode, agent mode;

3. Behavioral mode: template method mode, command mode, visitor mode, iterator mode, observer mode, mediator mode, memo mode, interpreter mode, state mode, strategy mode, chain of responsibility mode.

Note: The classification and name of different books may be different. "Design Patterns" has a special book.

 

1. Singleton mode

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

For example, SessionFactory of MyBatis, it mainly acts as a proxy for data storage sources and is responsible for creating Session objects. Under normal circumstances, we only need to use a SessionFactory object, so it is a singleton mode.

There are five main singleton modes: hungry style (subdivided into static constants and static code blocks), lazy style (subdivided into thread unsafe, synchronized methods, synchronized code blocks), double check, static inner classes, enumerations

 

Hungry Chinese

Static variable method

public class SingletonTest01 {
    
    
    public static void main(String[] args) {
    
    
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);//结果为true,两个对象相同
    }
}
//饿汉式(静态变量)
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static final Singleton instance = new Singleton();
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }
    //3. 对外提供唯一一个公共静态方法,来获得该类对象
    public static Singleton getInstance(){
    
    
        return instance;
    }
}

Advantages and disadvantages:

  1. Advantages: The writing method is simple, and the instantiation is completed when the class is loaded, avoiding thread synchronization problems.
  2. Disadvantages: it is instantiated when the class is loaded, and the effect of lazy loading is not achieved (the instance is created only when it is used, otherwise it is not created. If this instance has not been used, it will cause memory waste)
  3. Conclusion: this singleton modeAvailable, butmayCause a waste of memory.

 

Static code block

public class SingletonTest02 {
    
    
    public static void main(String[] args) {
    
    
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();
        System.out.println(singleton1 == singleton2);//结果为true,两个对象相同
    }
}

//饿汉式(静态代码块)
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static Singleton instance;
    //在静态代码块里实例化
    static {
    
    
        instance = new Singleton();
    }
    
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }
    //3. 对外提供唯一一个公共静态方法,来获得该类对象
    public static Singleton getInstance(){
    
    
        return instance;
    }
}

Advantages and disadvantages: The same as the static variable method, except that the class instantiation is placed in the static code block, but it is still instantiated when the class is loaded.

 

Lazy man

Thread unsafe

//饿汉式(静态代码块)
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static Singleton instance;
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }
    //3. 对外提供唯一一个公共静态方法,来获得该类对象。当使用到该方法时,才创建对象。
    public static Singleton getInstance(){
    
    
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

Advantages and disadvantages:

  1. It can play a lazy loading effect (it will only be created when the instance is used), but it can only be used in a single thread.
  2. In multi-threading, if a thread has entered the if, but has not yet executed new, and another thread is just making an if judgment, this may cause the first thread to succeed in new and the second thread to enter if, then the second instance of new. This destroys the singleton pattern.
  3. Conclusion: Do not use this method in actual development .

 

Synchronization method

//懒汉式(同步方法)
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static Singleton instance;
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }
    //3. 对外提供唯一一个公共静态方法,来获得该类对象
    //改为同步方法 synchronized
    public static synchronized Singleton getInstance(){
    
    
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

Advantages and disadvantages:

  1. Solve the problem of thread insecurity.
  2. The efficiency is too low. When each thread wants to obtain a class instance, due to the synchronized, it must be synchronized (waiting for the process using this method to run out). However, this method only needs to be synchronized at the time of instantiation, and then only returns to the instance, without synchronization.
  3. Conclusion: In actual development, it is not recommended to use.

 

Synchronization code block

//懒汉式(同步方法)
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static Singleton instance;
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }
    //3. 对外提供唯一一个公共静态方法,来获得该类对象
    //改为同步代码块
    public static synchronized Singleton getInstance(){
    
    
        if (instance == null){
    
    
            synchronized(Singleton.class){
    
    
                instance = new Singleton();
            }
        }
        return instance;
    }
}

This method does not even solve thread safety, because when the first thread is new, the second thread can still pass the if judgment, and then still new.

 

Double check

//双重检查
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static volatile Singleton instance;
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }
    //3. 对外提供唯一一个公共静态方法,来获得该类对象
    //加入双重检查代码,解决线程安全和懒加载问题,同时保证了效率
    public static Singleton getInstance(){
    
    
        if (instance == null){
    
    
            synchronized (Singleton.class){
    
    
                if (instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

 
Volatile keyword : The modification of a volatile variable by a thread will be immediately perceived by other threads, that is, there will be no dirty reading of data, thereby ensuring the "visibility" of the data.

Advantages and disadvantages:

  1. Double-Check is often used in multi-threaded development. We have performed two if judgments in the code. If there are three threads A, B, and C, when both A and B pass the first if, A enters the synchronization code block first. It exits after instantiation, and instance is not null after B enters the synchronization code block, which ensures thread safety. However, the subsequent C cannot pass the first if judgment, so the efficiency problem is solved.
  2. Realize thread safety, lazy loading, and high efficiency.
  3. Conclusion: In actual development, this singleton design pattern is recommended.

 

Static inner class

//静态内部类
class Singleton{
    
    
    //1. 在该类内部创建实例对象
    private static volatile Singleton instance;
    //2. 构造器私有化,使外部不能通过new创建对象
    private Singleton(){
    
    }

    //3. 编写静态内部类
    private static class SingletonInstance{
    
    
        private static final Singleton INSTANCE = new Singleton();
    }

    //4. 对外提供唯一一个公共静态方法,来获得该类对象
    public static Singleton getInstance(){
    
    
        return SingletonInstance.INSTANCE;
    }
}

Advantages and disadvantages:

  1. One of the characteristics of static inner classes is that they will not be loaded with the loading of external classes, that is, when Singleton is loaded, SingletonInstance will not be loaded, and will only be loaded when Singleton.INSTANCE is executed, thereby achieving a lazy loading effect.
  2. The static properties of the class will only be initialized when the class is loaded for the first time, so here JVM helps us ensure thread safety, because other threads cannot enter when the class is initialized.
  3. Realize thread safety, lazy loading, and high efficiency.
  4. Conclusion: Recommended.

 

enumerate

package design_partten.singleton.type8;

public class SingletonTest08 {
    
    
    public static void main(String[] args) {
    
    
        Singleton singleton1 = Singleton.INSTANCE;
        Singleton singleton2 = Singleton.INSTANCE;
        System.out.println(singleton1 == singleton2);//结果为true,两个对象相同
        singleton1.sayOk();
    }
}

//静态内部类
enum Singleton{
    
    
    INSTANCE;
    public void sayOk(){
    
    
        System.out.println("ok~");
    }
}

Advantages and disadvantages:

  1. Using the enumeration added in JDK1.5 to implement the singleton mode can not only avoid multi-thread synchronization problems, but also prevent deserialization from re-creating objects.
  2. Conclusion: Recommended.

 

JDK source code use of singleton mode

Runtime is the hungry man-style singleton mode, because it can guarantee that we will use it, so there will be no waste of memory, and thread safety can also be guaranteed.

1615209917646

 

summary

  • The singleton mode ensures that there is only one object of this class 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.
  • When you want to instantiate an object, you must remember to use the corresponding method of obtaining the object instead of using new.
  • Singleton mode usage scenarios: objects that need to be created and destroyed frequently; objects that are too time-consuming or resource-consuming to create objects, but need to be used frequently; tool objects; objects that frequently access databases or files (such as data Source, SessionFactory).

Guess you like

Origin blog.csdn.net/qq_39763246/article/details/114553165