Java: Simple understanding and use of Java singleton mode in java study notes

Java singleton pattern

1. The realization of Hungry Chinese singleton is as follows:

//饿汉式实现
public class SingleB {
    
    
    private static final SingleB INSTANCE = new SingleB();
    private SingleB() {
    
    }
    public static SingleB getInstance() {
    
    
        return INSTANCE;
    }
}

2. The ultimate lazy version: volatile

// Version 4 
public class Single4 {
    
    
    private static volatile Single4 instance;
    private Single4() {
    
    }
    public static Single4 getInstance() {
    
    
        if (instance == null) {
    
    
            synchronized (Single4.class) {
    
    
                if (instance == null) {
    
    
                    instance = new Single4();
                }
            }
        }
        return instance;
    }
}

insert image description here
The main reason lies in the sentence singleton = new Singleton(), which is not an atomic operation. In fact, this sentence probably does the following three things in the JVM:

  • 1. Allocate memory to singleton
  • 2. Call the constructor of Singleton to initialize member variables and form an instance
  • 3. Point the singleton object to the allocated memory space (singleton is non-null after executing this step)

But there are optimizations for instruction reordering in the JVM's just-in-time compiler. That is to say, the order of the second and third steps above cannot be guaranteed, and the final execution order may 1-2-3or be 1-3-2:

  • If it is the latter, it will be preempted by thread 2 before 3 is executed and 2 is not executed. At this time instance 已经是非 null了(但却没有初始化), thread 2 will directly return to instance, then use it, and then report an error logically.

Explain a little more, that is to say, because there is one 『instance已经不为null但是仍没有完成初始化』的中间状态, and at this time, if other threads happen to run to the first layer if (instance == null), the instance read here is no longer null, so directly If the instance in this intermediate state is used, problems will arise.

  • The key here is - thread T1 to instance 写操作没有完成, thread T2 就执行了读操作.

The role of the volatile keyword

One function of the volatile keyword is 禁止指令重排that after the instance is declared volatile, there will be one write operation on it 内存屏障, so that there is no need to call the read operation before its assignment is completed.

  • Note: volatileWhat prevents the reordering of instructions singleton = newSingleton()in this sentence , but ensures that it will not be called until one is complete .内部[1-2-3]写操作([1-2-3])读操作(if(instance == null))

3. Effective Java 1 - static inner class

// Effective Java 第一版推荐写法
public class Singleton {
    
    
    private static class SingletonHolder {
    
    
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton (){
    
    }
    public static final Singleton getInstance() {
    
    
        return SingletonHolder.INSTANCE;
    }
}

This way of writing is very clever:

  • For the inner class SingletonHolder, it is a hungry singleton implementation, which SingletonHolderwill ClassLoaderensure , making INSTANCEit a true singleton.
  • At the same time, since SingletonHolderit is an internal class, it is only used in () Singletonof the external class, so the timing when it is loaded is when the getInstance() method is called for the first time.getInstance
  • It uses ClassLoaderto ensure synchronization, while allowing developers to control the timing of class loading. From the inside, it looks like a hungry singleton, but from the outside, it is indeed a lazy implementation.

4.5.2 Effective Java 2 - Enumeration

// Effective Java 第二版推荐写法
public enum SingleInstance {
    
    
    INSTANCE;
    public void fun1() {
    
     
        // do something
    }
}

// 使用
SingleInstance.INSTANCE.fun1();

insert image description here

reference

1. Hi, let’s talk about Java’s singleton again

Guess you like

Origin blog.csdn.net/JMW1407/article/details/122524092