--- singleton design pattern (the Singleton) mode

Design pattern Singleton pattern is the simplest and most commonly used design patterns. Do you really know?
Hungry man with a lazy man style What is the difference, what advantages and disadvantages, you know?
In addition to these two kinds of writing, in fact, can also be achieved by enumerating go, static inner classes, you know?
to find out more, please read the following:

Singleton: ensure that only one instance of a class, and provide a global access point.

A. Single example of the advantages and disadvantages

1. Advantages

(1) provides controlled access to the only instance;
(2) Since there is only one object in system memory, so you can save system resources, some need to frequently create and destroy objects Singleton pattern certainly can improve system performance ;
(3) according to the actual needs can be extended on the basis of a single embodiment dual mode made on the embodiment mode, a multi-mode embodiment;

2. shortcomings

(1) functions singleton too heavy, which code may be too complex, contrary to the "single responsibility principle" to some extent.
(2) If an instance of an object for a long time not being used, the system will be considered garbage to be collected, which will result in the loss of the object's state.

II. Implementation

There are many ways to achieve single-mode embodiment, according to the needs of the scene, can be divided into two categories, 6 implementation. As follows (Click on image to enlarge view):
Here Insert Picture Description

Create a singleton (I) is initialized

1. hungry Chinese-style

(1) This embodiment is the simplest implementation of a single

(2) Principle: dependency JVM class loading mechanism to ensure the singleton will only be created once, that is thread-safe.

  • During the initialization phase initialization JVM class (ie after Class is loaded, the thread before use), it performs like
  • During initialization execution class, JVM will go to get a lock. The lock can be synchronized to initialize multiple threads of the same class

(3) code implementation:

代码片1
public class Singleton {
 
        // 1. 创建私有变量 ourInstance(用以记录 Singleton 的唯一实例)
       //  2. 内部进行实例化
        private static Singleton instance = new Singleton();

        //3. 把类的构造方法私有化,不让外部调用构造方法实例化
        private Singleton() {

       //4. 定义公有方法提供该类的全局唯一访问点
       //5. 外部通过调用getInstance()方法来返回唯一的实例
        public static Singleton getInstance() {
             return instance;
        }
    }

(4) application scenario
except when initialized singleton single exception is created, continues to extend out of the: singleton object requires fast initialization & small memory .

2. enumerated type

(1) according to the characteristics enumerated types, meet the required singleton create a singleton, thread-safe, to achieve simple demand

(2) code is as follows:

代码片2
public enum Singleton {
    //定义1个枚举的元素,即为单例类的1个实例
    INSTANCE;

    public void test() {
        //do something
    }
}

(3) This is the most simple, easy implementation singleton, borrow "Effective Java" words:
enum type single element has become the best way to achieve Singleton.

(II) as needed, to create a single retardation Example

3. The lazy man's (the underlying implementation)

(1) with the starving formula biggest difference is: the opportunity to create a single case

  • Starving type: single example creates opportunity uncontrollable, that is when the class is loaded automatically create a singleton
  • Lazy type: single example creates a controlled timing, when that is needed, just manually create a singleton

(2) code implementation:

代码片3
class Singleton {
    // 1. 类加载时,先不自动创建单例
   //  即,将单例的引用先赋值为 Null
    private static  Singleton ourInstance  = null;

    // 2. 构造函数 设置为 私有权限
    // 原因:禁止他人创建实例 
    private Singleton() {
    }
    
    // 3. 需要时才手动调用 newInstance() 创建 单例   
    public static  Singleton newInstance() {
    // 先判断单例是否为空,以避免重复创建
    if( ourInstance == null){
        ourInstance = new Singleton();
     }
     return ourInstance;
    }
}

(3) the shortcomings
to achieve foundation lazy man is not thread-safe, for the following reasons (Click on image to enlarge view):
Here Insert Picture Description
to achieve the foundation for the lazy style of writing, the following two kinds of solutions continue to look down.

4. Genlock (improved formula lazy)

(1) the principle of
using a synchronous lock synchronized method to create a single example of the lock, to prevent multiple threads simultaneously call, thereby avoiding a single case has been repeatedly create

  • That is, getInstance () method in a block can only be run threads
  • If the segment code is running in a thread, another thread tries to run a block of code, it will be blocked and have to wait
  • And in this thread-safe method where we achieve the creation of a single case, to ensure that the singleton object multithreaded mode and uniqueness

(2) code is as follows:

// 写法1
class Singleton {
    // 1. 类加载时,先不自动创建单例
    //  即,将单例的引用先赋值为 Null
    private static  Singleton ourInstance  = null;
    
    // 2. 构造函数 设置为 私有权限
    // 原因:禁止他人创建实例 
    private Singleton() {
    }
    
    // 3. 加入同步锁
    public static synchronized Singleton getInstance(){
        // 先判断单例是否为空,以避免重复创建
        if ( ourInstance == null )
            ourInstance = new Singleton();
        return ourInstance;
   }
}


// 写法2
// 该写法的作用与上述写法作用相同,只是写法有所区别
class Singleton{ 

    private static Singleton instance = null;

    private Singleton(){
    }

    public static Singleton getInstance(){
        // 加入同步锁
        synchronized(Singleton.class) {
            if (instance == null)
                instance = new Singleton();
        }
        return instance;
    }
}

(3) disadvantages of
each visit should be carried out thread synchronization (ie call synchronized lock), resulting in excessive synchronization overhead (= lock time-consuming, energy-consuming).

PS: Actually just need to synchronize only when the method is called the first time, once the singleton is created, there is no need for synchronization.

The double checking lock (improved formula lazy)

(1)原理
在同步锁的基础上,添加1层 if判断:首先检查实例已经被创建了,如果尚未创建,"才"进行同步,若单例已创建,则不需再执行加锁操作就可获取实例(===>即:只有第一次会同步),从而提高性能。

(2)代码实现:

public class Singleton2 {
    
    private volatile static Singleton2 ourInstance = null;

    private Singleton2() {
    }

    public static Singleton2 newInstance() {
        // 加入双重校验锁
        // 校验锁1:第1个if
        if (ourInstance == null) {  // ①
            synchronized (Singleton2.class) { // ②
                // 校验锁2:第2个 if
                if (ourInstance == null) {
                    ourInstance = new Singleton2();
                }
            }
        }
        return ourInstance;
    }

    // 说明
    // 校验锁1:第1个if
    // 作用:若单例已创建,则直接返回已创建的单例,无需再执行加锁操作
    // 即直接跳到执行 return ourInstance

    // 校验锁2:第2个 if 
    // 作用:防止多次创建单例问题
    // 原理
    // 1. 线程A调用newInstance(),当运行到②位置时,此时线程B也调用了newInstance()
    // 2. 因线程A并没有执行instance = new Singleton();,此时instance仍为空,因此线程B能突破第1层 if 判断,运行到①位置等待synchronized中的A线程执行完毕
    // 3. 当线程A释放同步锁时,单例已创建,即instance已非空
    // 4. 此时线程B 从①开始执行到位置②。此时第2层 if 判断 = 为空(单例已创建),因此也不会创建多余的实例
}

其中第2行代码的java关键字volatile 简单说明一下:
volatile关键字确保,当ourInstance 变量被初始化成Singleton2 实例时,多个线程正确地处理ourInstance 变量。

当性能是你关注的重点,这种写法就可以大大帮你介绍newInstance的时间消耗。

(3)缺点:
没什么明显缺点,就写法有点复杂,容易出错。

6. 静态内部类

(1)原理
根据 静态内部类 的特性,同时解决了按需加载、线程安全的问题,同时实现简洁

  • 在静态内部类里创建单例,在装载该内部类时才会去创建单例。
  • 线程安全:类是由 JVM加载,而JVM只会加载1遍,保证只有1个单例。

(2)代码实现

public class Singleton3 {
    
    // 1. 创建静态内部类
    private static class SingleTonHoler{
        // 在静态内部类里创建单例
        private static Singleton3 INSTANCE = new Singleton3();
    }

    // 私有构造函数
    private Singleton3(){}

    // 延迟加载、按需创建
    public static Singleton3 getInstance(){
        return SingleTonHoler.INSTANCE;
    }
}

// 调用过程说明:
// 1. 外部调用类的getInstance 
// 2. 自动调用SingleTonHoler.INSTANCE
// 2.1 此时单例类Singleton3得到初始化
// 2.2 而该类在装载 & 被初始化时,会初始化它的静态域,从而创建单例;
// 2.3 由于是静态域,因此只会JVM只会加载1遍,Java虚拟机保证了线程安全性
// 3. 最终只创建1个单例

(3)缺点:
静态内部类有一个致命的缺点,就是传参的问题,由于是静态内部类的形式去创建单例的,故外部无法传递参数进去,例如Context这种参数,所以,我们创建单例时,可以在静态内部类与DCL模式里自己斟酌。

关于静态内部类创建单例模式,推荐大家阅读以下文章,可以更加深入的理解:
深入理解单例模式:静态内部类单例原理

三.总结:

本文主要对 单例模式 进行了全面介绍,包括原理 & 实现方式。对于实现方式,此处作出总结(图片点击可放大查看):
Here Insert Picture Description

Published 81 original articles · won praise 37 · views 50000 +

Guess you like

Origin blog.csdn.net/gaolh89/article/details/93235424