The singleton mode is believed to be the one that many programmers are exposed to the most, and it is also the one that is examined most frequently in the interview process. I wonder if you have ever been asked this interview question? Welcome to comment.

Today we’re going to focus on a few questions about singletons and how to implement them correctly, and then you’re going to look back and see if you answered or used them correctly.

Why use singletons

Singletons are very simple. A class allows only one object or instance to be created. This class is a singleton class. This design pattern is called the singleton design pattern. It is the first design pattern of creation, or singleton for short.

When is the singleton pattern used? Or why use singletons in this case?

  1. For example, we now use the printer in the Java processing program, and our server is multi-threaded, but there is only one printer, can not repeatedly create printer resources ah. Of course, we can also define a normal class and add the synchronized keyword in the call print.
  2. Globally Unique Classes Sometimes, when we are doing business design, we should only keep one copy of data in the system, and then we should design it as a singleton. For example, the configuration information class, the system configuration file should only have one copy, after loading into memory in the form of an object, of course, there is only one copy. For example, we design a lottery system, each click to generate a lottery number, you can design a singleton, internal storage of all the number, each time a random number out. If you use a generic class object, you need to share all the lottery numbers through shared memory.

How do I write a singleton?

Learning anything, because the capacity of the brain is limited, first of all, we need to understand the concept, know why, after the pursuit of how to do, how to achieve, do the process may be very complicated, such as one, two, three, four and five steps, but we need to simplify, summarize and simplify.

Singletons need to consider the following issues:

  • The constructor should be private, so that the external instance can not be created by new, otherwise it can be created by others.
  • Whether there are thread safety issues when creating multiple threads.
  • Is lazy loading supported?
  • Is getInstance() high performance?

Singleton typical implementation

The hungry type

The instance is initialized in advance, so there is no way to delay loading. Lazy loading is not supported. Some people say that this way is not good, saying that I did not use singletons, you have loaded me, waste ah. But on the plus side, loading the class in ahead of time exposes the problem, so that if there is a problem with the design of the class, it will be reported when the program starts, rather than when it runs.

public class SingleTon {
    private static final SingleTon instance = new SingleTon();
    
    private SingleTon(a) {}
    
    public static SingleTon getInstance(a) {
        return instance;
    }
    
    public void method(a) {}}Copy the code

LanHanShi

The so-called lazy, that is to support lazy loading. The general idea is similar, but inside the class instance is not instantiated by default.

public class SingleTon {
    private static SingleTon instance;

    private SingleTon(a) {}

    public static synchronized SingleTon getInstance(a) {
        if (instance == null) {
            instance = new SingleTon();
        }
        return instance;
    }

    public void method(a) {}}Copy the code

Why synchronized? If multiple threads call getInstance() at the same time, there will be a concurrency problem. Multiple threads may getInstance == null at the same time, which will result in repeated instantiations. So in order to solve the problem of multi-threaded concurrency, performance is sacrificed here, and strict serialization is adopted. Performance is very low in multithreading.

Double check slob

Lazy loading is not supported in hungry mode. Lazy mode, low performance under multithreading, how to modify it, is the improved lazy mode, also called double detection. So how do we do that?

public class SingleTon {
    private static volatile SingleTon instance;

    private SingleTon(a) {}

    public static SingleTon getInstance(a) {
        if (instance == null) {
            synchronized (SingleTon.class) {
                if (instance == null) {
                    instance = newSingleTon(); }}}return instance;
    }

    public void method(a) {}}Copy the code

Volatile is critical in this class. If instance = new SingleTon() is executed by thread 1 without the volatile keyword; Thread 2 determines that instance is no longer null and returns instance directly, but instance is not initialized. Because there are three steps to initialize an object:

  • Allocate memory
  • Memory initialization
  • The object points to the newly allocated memory address

Since it is divided into three steps, it is not an atomic operation, and an instruction rearrangement may occur, which means that the third step may be executed first, at which point other threads will determine that instance is not null. Adding the volatile keyword, which prevents machine instruction reordering, eliminates this problem.

Static inner class

This approach, which avoids double checking, utilizes Java static inner classes, similar to hanhan-style, and achieves lazy loading.

public class SingleTon {

    private SingleTon(a) {}
    
    private static class SingleTonHolder {
        private static final SingleTon instance = new SingleTon();
    }

    public static SingleTon getInstance(a) {
        return SingleTonHolder.instance;
    }

    public void method(a) {}}Copy the code

Doesn’t it feel neat? When the SingleTon class is loaded, the SingleTonHolder class is not loaded. The SingleTonHolder class is only loaded when the getInstance method is called, and the instance is created. This is guaranteed by the JVM.

Enumeration methods

A simpler, but perhaps confusing, constructor for an enumeration is private by default. Java’s enumerated types themselves guarantee thread-safety and instance uniqueness. With a few simple lines, you can use the method to enumerate singletons.

public enum SingleTon {
    INSTANCE;
    
    public void method(a) {}}Copy the code

But is the singleton really good? Next we will discuss why the singleton pattern is not recommended. How to replace, and how to achieve the distributed singleton pattern under the cluster?

Programmers’ partners, the way of learning, the more peers can go further, join the public number [programmer’s way], communication together, out of our programmer’s way!