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

Singleton mode


May 27, 2021 Design mode


Table of contents


Singleton mode

Singleton Pattern is one of the simplest design patterns in Java. This type of design pattern belongs to the creation pattern and provides the best way to create objects.

This pattern involves a single class that is responsible for creating its own objects while ensuring that only a single object is created. This class provides a way to access its unique objects, which can be accessed directly without the need to instantiate the objects of the class.

Attention:

  • 1, a single class can only have one instance.
  • 2, single-case class must create their own unique instance.
  • 3, a single case class must provide this instance to all other objects.

Introduced

Intent: Guarantee that a class has only one instance and provide a global access point to access it.

Main solution: A globally used class is frequently created and destroyed.

When to use: When you want to control the number of instances and save system resources.

How to resolve: Determine if the system already has this single case, return if it does, and create it if not.

Key code: The constructor is private.

Application example: 1, a party can only have one chairman. 2 , Windows is multi-process multi-threaded, in the operation of a file, it is inevitable that multiple processes or threads at the same time to operate a file phenomenon, so all files must be processed through a unique instance. 3 , some device managers are often designed as a single-case mode, such as a computer has two printers, in the output of the processing can not be two printers to print the same file.

Pros: 1, there is only one instance in memory, reducing memory overhead, especially frequent creation and destruction of instances (such as the School of Management home page cache). 2 , avoid the multiple use of resources (such as writing files).

Cons: No interface, no inheritance, conflict with the principle of single responsibility, a class should only care about internal logic, not how to instantiate outside.

Use scenario: 1, requires the production of a unique serial number. 2 , the counter in the WEB, do not have to refresh in the database once, with a single case to cache first. 3 , the creation of an object needs to consume too many resources, such as I/O and database connection.

Note: The getInstance() method requires the use of a sync lock synchronized (Singleton .class) to prevent multiple threads from entering at the same time causing instances to be instantiated multiple times.

Realize

We'll create a SingleObject class. ject class has its private constructor and a static instance of itself.

The SingleObject class provides a static method for the outside world to get its static instances. Singleton PotternDemo, our demo class uses the SingleObject class to get singleObject objects.

Singleton mode

Step 1

Create a Singleton class.

SingleObject.java

public class SingleObject {

   //创建 SingleObject 的一个对象
   private static SingleObject instance = new SingleObject();

   //让构造函数为 private,这样该类就不会被实例化
   private SingleObject(){}

   //获取唯一可用的对象
   public static SingleObject getInstance(){
      return instance;
   }

   public void showMessage(){
      System.out.println("Hello World!");
   }
}

Step 2

Get the unique object from the singleton class.

SingletonPatternDemo.java

public class SingletonPatternDemo {
   public static void main(String[] args) {

      //不合法的构造函数
      //编译时错误:构造函数 SingleObject() 是不可见的
      //SingleObject object = new SingleObject();

      //获取唯一可用的对象
      SingleObject object = SingleObject.getInstance();

      //显示消息
      object.showMessage();
   }
}

Step 3

Verify the output.

Hello World!

Several ways to implement a singleton pattern

There are several ways to implement a singleton pattern, as follows:

1, lazy, thread is not safe

Whether Lazy Initialization: Yes

Whether multithreaded is safe: No

Difficulty: Easy

Description: This approach is the most basic implementation, and the biggest problem with this implementation is that it does not support multithreaded. Because there is no locked synchronized, it is not strictly a single case pattern.
This approach lazy loading is obvious and does not require thread safety and does not work properly on multiple threads.

Examples of code:

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
  
    public static Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
}  

The following implementations support multithreaded implementations, but differ in performance.

2, lazy, thread-safe

Whether Lazy Initialization: Yes

Whether multithreaded is safe: Yes

Difficulty: Easy

Description: This approach has a good lazy loading that works well in multiple threads, but is inefficient and does not require synchronization in 99% of cases.
Pros: The first call is initialized to avoid memory waste.
Cons: Locks must be added to ensure a single case, but locking can affect efficiency.
The performance of getInstance() is not critical to the application (this method is used less frequently).

Examples of code:

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}  
    public static synchronized Singleton getInstance() {  
    if (instance == null) {  
        instance = new Singleton();  
    }  
    return instance;  
    }  
} 

3, hungry Han style

Whether Lazy Initialization: No

Whether multithreaded is safe: Yes

Difficulty: Easy

Description: This method is commonly used, but prone to garbage objects.
Pros: Without locking, execution efficiency is improved.
Cons: The class is initialized when it loads, wasting memory.
It is based on the classloder mechanism to avoid multithreaded synchronization problems, however, instance is instantiated when the class is loaded, although there are many reasons for class loading, most of which are called getInstance methods in single-case mode, but it is not certain that there are other ways (or other static methods) that cause class loading, when initializing instance obviously does not have the effect of lazy loading.

Examples of code:

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}  

4, double check lock / double check lock (DCL, i.e. double-checked locking)

JDK version: JDK1.5

Whether Lazy Initialization: Yes

Whether multithreaded is safe: Yes

Difficulty: More complex

Description: This approach uses a dual-lock mechanism that is safe and maintains high performance in multithreaded situations.
The performance of getInstance() is critical to the application.

Examples of code:

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}  

5, registration/ static internal class

Whether Lazy Initialization: Yes

Whether multithreaded is safe: Yes

Difficulty: General

Description: This approach achieves the same effect as a double lock check, but the implementation is simpler. D elayed initialization is used for static domains and should be done in this way instead of double-locking. This approach applies only to static domains, and double locking can be used when the instance domain needs to delay initialization.
This approach also leverages the classloder mechanism to ensure that there is only one thread at the time of initialization of the instance, unlike the third way: as long as the Singleton class is mounted, the instance is instantiated (without the lazy loading effect), and in this way the Singleton class is loaded and the instance is not necessarily initialized. B ecause the Singleton Holder class is not actively used, the singletonHolder class is displayed only when the singletonHolder class is displayed by calling the getInstance method, instantiated by instance. I magine if instantiation instance is resource-consuming, so you want it to be lazy to load, and on the other hand, you don't want to instantiate when the Singleton class loads, because you can't guarantee that the Singleton class might be actively used elsewhere to load, then instantiation instance is obviously inappropriate at this time. At this point, this approach makes sense compared to the 3rd way.

Examples of code:

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}   

6, enumerity

JDK version: JDK1.5

Whether Lazy Initialization: No

Whether multithreaded is safe: Yes

Difficulty: Easy

Description: This implementation has not been widely adopted, but this is the best way to implement a single-case pattern. It's simpler, automatically supports serialization mechanisms, and absolutely prevents multiple instantiations.
This approach, advocated by Josh Bloch, author of Effective Java, not only avoids multithreaded synchronization issues, but also automatically supports serialization mechanisms that prevent antiserration from recreating new objects and absolutely prevents multiple instantiations. However, since JDK 1.5 does not add enum features until later, writing in this way can feel rusty and rarely used in practice.
Private construction methods cannot be called by reflection attack.

Examples of code:

public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}  

Empirical: In general, the 1st and 2nd lazy methods are not recommended, and the 3rd hungry people method is not recommended. T he fifth registration method is used only if the lazy loading effect is explicitly implemented. I f it comes to creating objects with antiseration, you can try the 6th enumeration method. If you have other special needs, consider using the 4th double lock method.