Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Get started with the single-case pattern


May 30, 2021 Article blog


Table of contents


What is a single-case pattern?

  • Singleton Pattern is a relatively simple pattern that is widely used in practice, such as the Bean instance in Spring as a singleton object.
  • Definition: Ensure that a class has only one instance and instantiates itself and makes it available to the entire system.

The pros and cons of a single-case pattern

merit

  • There is only one instance, reducing memory overhead, especially frequently creating and destroying instances.
  • Single-case mode avoids multiple consumption of resources, such as a write-to-file action, because only one instance exists in memory, and avoids simultaneous writes to the same resource file.
  • Single-case mode allows the system to set global access points, optimize and share resource access, for example, by designing a single-case class that is responsible for mapping all data tables.

shortcoming

  • Single-case modes generally do not have an interface and are difficult to extend (depending on the environment).
  • The single-case model conflicts with the principle of single responsibility. A class should implement only one logic, regardless of whether it is a single case.

The implementation of a single-case pattern

  • There are many implementations for a single-case pattern, but each implementation has its advantages and disadvantages, so let's look at the various implementations.
  • The implementation of the single-case pattern satisfies the following: the construction method is private. T here is a static method to get an instance of the class. This class guarantees only one instance.

Lazy

  • Lazy is created when this object is used.
  • Lazy, it is created for you (because it is lazy) when a single-case pattern class instance is required.
  • Pros: This object is created only when used, saving resources.
  • The simple implementation is as follows:
/**
  *Singleton类,单例模式类,在类加载时便会创建一个私有静态变量instance,也就是该类的实
  *例,再通过公共接口getInstance()来发布该实例
  */
public class Singleton {  
    private static Singleton instance;
    //私有化构造方法防止外界new对象
    private Singleton (){

    }

    //公有化静态函数,对外暴露单例对象的接口

    public static Singleton getInstance() {

        if (instance == null) {

            instance = new Singleton();

        }

        return instance;

    }

However, this approach does not guarantee that this is the only single case, in high concurrent access, multiple threads access to this single case at the same time, there is still no guarantee that this class is a single case

In order to ensure thread safety, we can add a lock, to this getInstance() method plus thread synchronization lock synchronize implementation as follows:

public class Singleton {  

    private static Singleton instance;  

    private Singleton (){

        

    }  

    public static synchronized Singleton getInstance() {  

    if (instance == null) {  

        instance = new Singleton();  

    }  

    return instance;  

    }  

}

However, once locked, although can guarantee that in fact a single case and thread-safe, but in high concurrent access performance must be affected, multiple threads need to use the single case, can not guarantee speed, need to wait synchronously for this single case to use back to the JVM heap (Heap) can continue to use this single case, the efficiency is very low.

There is also a double check, two judgments

Double Check Lock (DCL) implements a single-case pattern

public class Singleton{

    private volatile static Singleton instance;

    private Singleton(){

        

    }

    public static Singleton getInstance(){

        if(instance == null){

            synchronized (Singleton.class){

                if(instance == null){

                    instance = new Singleton();

                }

            }

        }

        return instance;

    }

}

We can see that the instance has been judged twice in gettance is empty, the first judgment is mainly to avoid unnecessary synchronization problems, the second judgment is to create instances in the case of null, because in some cases there will be failure problems, namely DCL failure problems, you can use the vollatile keyword to deal with this problem, but the same, the use of volateile keywords will also have some impact on performance. However, the advantage is that the resource utilization is high, the object is instantiated the first time the getInstance is executed, but the DCL also because the first load response is slow, so in the case of high concurrence will also have some defects.

Hungry Chinese style

  • Hungry and lazy happen to be the opposite, creating instances when classes load.
  • The single-case pattern class can't wait to create an instance (because it's hungry)
  • Pros: Create before you use it, wasting resources.
  • Cons: Created when the class is loaded, thread-safe.
  • The implementation is as follows:

/**

  *这种方式在类加载时就完成了初始化,所以类加载较慢,但是获取对象的速度快。这种方式

  *基于类加载机制,避免了多线程的同步问题。如果从来没有使用过这个实例,则会造成内存

  *的浪费。

  */

public class Singleton {  

    private static Singleton instance = new Singleton();  

    private Singleton (){

        

    }  

    public static Singleton getInstance({  

     return instance;  

    }  

}

Anonymous internal class/static inner class

  • Using static variables, static blocks of code, and static methods are principles that load only once when a class loads.
  • The implementation is as follows

public class Singleton {

    private static Singleton instance;

    //静态块在类加载时会被执行,也就创建了Singleton类实例

    static{

        instance = new Singleton();

    }

    private Singleton (){

    

    }  

    public static final Singleton getInstance() {  

     return SingletonHolder.INSTANCE;  

    }  

}


/**

  *Java静态内部类的特性是,加载的时候不会加载内部静态类,使用的时候才会进行加载。

  *第一次加载Singleton类时并不会初始化sInstance,只有第一次调用getInstance方法时虚

  *拟机加载SingletonHolder并初始化sInstance。这样不仅能确保线程安全,也能保证

  *Singleton类的唯一性。所以,推荐使用静态内部类单例模式

  */

public class Singleton {  

    private static class SingletonHolder {  

     private static final Singleton INSTANCE = new Singleton();  

    }

    private Singleton (){

    

    }  

    public static final Singleton getInstance() {  

     return SingletonHolder.INSTANCE;  

    }  

}

Enumerate the single-case pattern

/**
  *默认枚举实例的创建是线程安全的,并且在任何情况下都是单例。
  *枚举单例的有点就是简单,缺点是可读性不高。
  */
public enum Singleton {
    //外部调用由原来的Singleton.getInstance变成了Singleton.INSTANCE了。
    INSTANCE;
}

summary

Single-case mode is a pattern that uses a high frequency, and in our clients there is usually no high concurring situation, so choosing which method does not have much impact. For efficiency reasons, it is recommended to use a single-case pattern for static internal classes and a single-case pattern for DCL.

merit:

  • Because the single-case pattern has only one instance in memory, the advantages of the single-case pattern are obvious because memory expenses are reduced, especially when an object needs to be created, destroyed frequently, and performance cannot be optimized when it is created or destroyed.
  • Because the single-case pattern generates only one instance, the performance overhead of the system is reduced, and when an object is generated with more resources, such as reading configurations and generating other dependent objects, it can be resolved by generating a single-case object directly at app launch and then permanently reside.
  • Single-case mode avoids multiple consumption of resources, such as the operation of a file, because only one instance exists in memory, and avoids simultaneous operations on the same resource file.
  • Single-case mode allows the system to set global access points, optimize and share resource access. For example, you can design a single-case class that is responsible for mapping all data tables.

shortcoming:

  • Single-case patterns generally do not have an interface, and scaling is difficult unless the code is modified.
  • If a single-case object holds Context, it is easy to cause a memory leak, and it is important to note that theContext passed to a single-case object is preferably the ApplicAtion Context.
  • Not suitable for frequently changing objects, if the instantiated object is not utilized for a long time, the system will consider the object to be garbage and recycled, which may lead to the loss of object state;

Use the scene

  • Site visits counter.
  • The class used in the project to read the profile.
  • In Spring, each Bean defaults to a single case, making it easy for spring containers to manage.

Recommended good lessons: Java: 23 days zero foundation fully introductory, Java interview basic questions should be informed