First, early review

The previous article, “The Beginning of the Java Design Pattern”, introduced the six principles of design, namely, single responsibility, Richter’s substitution principle, dependency inversion, Demeter’s Rule, interface isolation, open closed principle. Each principle is reflected in detail through the definition interpretation and code actual combat, and finally summarized the six principles, the principle is dead, people are alive, we should use the six principles according to the actual situation, not mechanically, for the principle and principle, for the mode and mode. In this article, we will introduce the simplest design pattern, the singleton pattern.

Second, interpretation and actual combat

  • 2.1 Definition of singleton mode

Ensure a class has only instance,and provide a global point of access to it. This translates to ensuring that a class has only one instance and that it instantiates itself and provides that instance to the entire system.

  • 2.2 Application Scenarios of singleton Mode

The application scenarios of singleton mode can be expressed in a sentence. If a class has multiple objects, the singleton mode should be adopted. The general scenarios are as follows:

A. Creating an object consumes a lot of resources or time, such as I/O and database connections.

B. Generate unique ids.

C. Tool classes, generally can be used to meet the static class.

  • 2.3 Actual combat of singleton mode

Let’s design a singleton mode, scene: in ancient China, generally, there can only be one emperor at a certain time, except for special circumstances, whether ministers or civilians, the emperor is the same, we use code to achieve this scene

Public void sayCommand(String STR); public void sayCommand(String STR); } public class MingEmperor implements Iemperor {private static MingEmperor =new MingEmperor(new) Random().nextInt(10)+""); Private String id; Private MingEmperor(String id) {this.id = id; } @Override public void sayCommand(String str) { System.out.println(str+"---------- I am the emperor, here is my ID ="+id);
    }
    public static MingEmperor getEmperor() {returnemperor; Public class Client {public static void main(String[] args) {for (int i = 0; i <10 ; i++) {
            MingEmperor.getEmperor().sayCommand("To see the Emperor."); }}}Copy the code

Execute the following scenario class, and the output is

public class MingEmperor implements Iemperor { private static MingEmperor emperor; Private String id; Private MingEmperor(String id) {this.id = id; } @Override public void sayCommand(String str) { System.out.println(str+"---------- I am the emperor, here is my ID ="+id);
    }
    public static MingEmperor getEmperor() {if (emperor==null){
            emperor= new MingEmperor(new Random().nextInt(10)+"");
        }
        returnemperor; }}Copy the code

When we get the emperor object, we check whether it is empty. If it is empty, we create a new object. Otherwise, we return the previously instantiated object. We run according to the original scene class, and the result is as follows:

This is what we expected. Is that ok? Since it’s a singleton, it must be a singleton in a multithreaded environment, so let’s try multithreading instead.

 public static void main(String[] args) {
        for (int i = 0; i <10 ; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    MingEmperor.getEmperor().sayCommand("To see the Emperor."); } }).start(); }}Copy the code

Execution Result:

Public class MingEmperor implements Iemperor {private static volatile MingEmperor implements Iemperor; Private String id; Private MingEmperor(String id) {this.id = id; } @Override public void sayCommand(String str) { System.out.println(str+"---------- I am the emperor, here is my ID ="+id);
    }
    public static synchronized MingEmperor getEmperor() {ifSynchronized (MingEmperor ==null){// synchronize (MingEmperor. Class){// synchronize (MingEmperor. Class){ It violates the singleton.if (emperor==null) emperor= new MingEmperor(new Random().nextInt(10)+""); }}returnemperor; }}Copy the code

We added volatile to the global variable, which is used to increase visibility between threads and prevent instruction reordering (more on volatile variables in a future article). In addition, the scope of synchronized is narrowed to use synchronized code blocks. This completes the thread-safe lazy singleton pattern known as double-checked locking (DCL).

In fact, if we take a look at this part of the code with the knowledge of the previous article, we find that the singleton pattern violates a principle, namely the single responsibility principle, according to the single responsibility principle, the emperor class does not care about singleton, not only the case, I just want to convey the command. So this model also teaches you to be flexible with your principles.

  • 2.4 Disadvantages of the singleton pattern

1. As mentioned above, the singleton pattern violates the single responsibility.

2. Singleton mode strictly speaking, there is no interface, can only be modified to extend, although the above example implements the interface, but can not make a singleton mode for the interface, because the singleton mode requires “self-instantiation”, interface and abstract class is not instantiated. So the singleton pattern in each implementation class, even if the interface is implemented, each implementation class has to implement its own set of singleton logic, that is, code duplication.

  • 2.5 Advantages of singleton mode

The singleton mode has the main advantages of reducing system resource consumption and optimizing system performance.

Third, summary

In fact, the pooling technique we use can be understood as an extension of the singleton pattern, which allows the creation of a specified number of instances, whereas the singleton pattern is equivalent to pooling one. So the pattern is to digest and understand and then be flexible with it. It is also important to note that when designing the singleton pattern, we need to take into account one case that breaks the singleton pattern, namely cloning. Although we have privatized the constructor, cloning objects do not need to execute the constructor, so this is also a potential way to break the singleton pattern. The solution is that the singleton class does not implement the Cloneable interface.

Four, reference

Zen of Design Patterns

6. Recommended reading

The Beginning of JAVA Design Patterns

Introduction to Java Collections: ArrayList

HashMap takes you into Java Collections

Java Lock ReentrantLock (part 1)

Java Lock ReentrantLock (part 2)

Java Lock ReentrantReadWriteLock

Introduction to JAVA NIO Programming (PART 1)

Introduction to JAVA NIO Programming (Part 2)

Introduction to JAVA NIO Programming (3)