Introduction to 23 design modes — single case mode

Time:2022-4-30

Singleton modeSome methods are adopted to make the software run:Only one instance object can exist in a classAnd this class can only provide one method to get an instance.

classification

  • Hungry Han style
    1. Static constant mode
    2. Static code block mode
  • Lazy style
    1. Normal mode, thread unsafe
    2. Synchronization method, thread safety
    3. Synchronous code block mode, thread unsafe
  • Other ways
    1. duplication check
    2. Static inner class
    3. enumeration

Realization idea:

  1. If you want to implement singleton, you can’t let the outside instantiate the object at will. So needConstructor private

  2. Since external creation is not allowed, you need toCreate an object inside a class

  3. External objects need to be used, soProvide an external method to obtain an instance

1、 Hungry Han style

According to the time when the object is created, it can be divided into hungry and lazy. Hungry Chinese style, that is, create an instance immediately when the class is loaded. According to the knowledge learned, we can quickly think of using itstaticKeyword associates an attribute with a class. The following two writing methods are provided for reference.

characteristic

  • Advantages: the writing method is simple, and the instantiation is completed when the class is loaded, avoiding the problem of thread synchronization
  • Disadvantages: the instantiation is completed when the class is loaded. If this instance is not used from the beginning to the end, it will cause a waste of memory

1. Static constant mode

class Singleton01{
    //Constructor private to prevent external new
    private Singleton01(){

    }
    //Create objects internally
    private final static Singleton01 instance = new Singleton01();

    //Provides static methods for creating instances externally
    public static Singleton01 getInstance(){
        return instance;
    }

}

2. Static code block mode

class Singleton02{
    //Constructor private to prevent external new
    private Singleton02(){

    }
    //Create objects internally
    private static Singleton02 instance;
    static {
        instance = new Singleton02();
    }

    //Provides static methods for creating instances externally
    public static Singleton02 getInstance(){
        return instance;
    }

}

This method has the same logic and advantages and disadvantages as the implementation method of static constants, but the writing method is different.

2、 Lazy style

Lazy, that is, the object is not instantiated when the class is loaded, and it is instantiated only when the object instance is used, which is also called lazyLazy loadingeffect. The benefits of this can save resources and reduce waste. It can be created only when necessary, and it will not be instantiated if it is not needed.

1. Normal mode (thread unsafe)

class Singleton01{
    //Constructor private
    private Singleton01(){

    }
    //Define static variables and instantiate the getInstance method to get the instance, which has the effect of lazy loading
    private static Singleton01 instance;

    public static Singleton01 getInstance(){
        //Judge if it is empty to create it, which plays a role in lazy loading
        if (instance == null){
            instance = new Singleton01();
        }

        return instance;
    }
}

Question:In the case of multithreading, it is assumed that the class has not been instantiated for the first time, and the two processes are executed at the same timeif(instance==null), but before the execution, both checks are valid and instantiation will be performed, which may lead to the problem of creating multiple instances.

2. Synchronization method (thread safety)

Since there is a thread safety problem, you will definitely think of using itsynchronizedKeyword to solve

class Singleton02{
    private static Singleton02 instance;

    private Singleton02(){

    }
    //Use the synchronized keyword for thread safety
    public static synchronized Singleton02 getInstance(){
        if (instance == null){
            instance = new Singleton02();
        }
        return instance;
    }
}

This method can achieve the effect of thread safety, but each thread needs to wait for the lock, so it will have the problem of low efficiency. Therefore, someone thought of narrowing the scope of the lock to the interior of the method and using synchronous code blocks

3. Synchronous code block mode (thread unsafe)

Is this a good way? Look at the code first

class Singleton03{
    private static Singleton03 instance;

    private Singleton03(){

    }

    public static Singleton03 getInstance(){
        if (instance == null){
            //In fact, synchronized here has no practical significance, and multiple instances may be generated
            synchronized (Singleton03.class){ 
                instance = new Singleton03();
            }
        }
        return instance;
    }
}

In this way, the scope of the lock becomes smaller, but multiple threads will judge it at the same timeif (instance == null), even if the lock is added later, the instance will still be created later, which is just a little delayed, so this writing methodUndesirable

3、 Other ways

1. Double check

In order to achieve the effect of lazy loading and give consideration to efficiency, this writing method appears

class Singleton01{
    //Volatile, which is immediately stored in memory when something changes. Prevent instruction rearrangement
    private static volatile Singleton01 instance;

    private Singleton01(){

    }

    //Double check to solve the problem of thread synchronization and ensure efficiency
    public static Singleton01 getInstance(){
        If (instance = = null) {// check for the first time to reduce the probability of lock generation
            synchronized (Singleton01.class){
                If (instance = = null) {// check the second time to ensure thread safety
                    instance = new Singleton01();
                }
            }
        }
        return instance;
    }
}

Using double check, the first check improves efficiency, and the second check ensures thread safety. It’s just beautiful

2. Static internal class

Using the static internal class, it will be loaded only when called, that is, there is a lazy loading effect, so it can also be written like this

class Singleton02{
    private Singleton02(){

    }

    /*
        Static internal classes will not be executed immediately when external classes are loaded, which plays the role of lazy loading.
        The static properties of a class can only be loaded when it is first used. The JVM is thread safe when the class is loaded
     */
    private static class SingletonInstance{
        private static final Singleton02 INSTANCE = new Singleton02();
    }

    public static Singleton02 getInstance(){
        return SingletonInstance.INSTANCE;
    }

}

3. Enumeration

Enumeration is the simplest way of writing, and it is also respected by many people

enum Singleton03{
    INSTANCE;
}

Simple and clear

4、 Summary

Using singleton mode, you can make a class have only one instance object, which saves system resources.

There are eight writing methods listed above. Among them, the writing method of lazy loading has thread safety and efficiency problems and needs to be used with caution. There are five recommended writing methods:Lazy loading 2 + other 3。 When the object identified as a singleton is bound to be used in the software, lazy loading can be used; otherwise, other methods can be used

Recommended Today

CommunityToolkit.Mvvm-IOC

CommunityToolkit.Mvvm does not have IOC built in, you can use Microsoft.Extensions.DependencyInjection. Register ViewModel and other services in App public partial class App : Application { public App() { Services = ConfigureServices(); this.InitializeComponent(); } public new static App Current => (App)Application.Current; public IServiceProvider Services { get; } private IServiceProvider ConfigureServices() { var sc = new ServiceCollection(); […]