一、为什么要使用单例设计模式?
    当多个线程要操作同一对象,要保证对象的唯一性,以解决实例化过程中只实例化一次。

    二、解决思路

    1. 1、有一个实例化的过程(只有一次),产生实例化对象。
    2. 2、提供返回实例对象的方法

    二、单例模式的分类

    1、饿汉式(可以深入了解JVM ClassLoader的加载机制)

    示例代码如下:

    /*
    饿汉模式
    1.线程安全性:在加载的时候已经被实例化(只有这一次),所以是线程安全的。
    2.性能:没有延迟加载,若长时间不使用,实例对象会占用资源,影响性能。
    */
    public class HungerySingleton {
    // 在加载的时候就产生实例对象(由ClassLoader加载)
    private static HungerySingleton instance = new HungerySingleton();

    // 实例的属性会占用资源空间
    private byte[] data = new byte[1024];

    private HungerySingleton {

    }

    // 返回实例对象
    public static HungerySingleton getInstance() {
    return instance;
    }

    // 测试20个线程会返回同一个实例对象
    public static void main(String[] args) {
    for (int i = 0; i < 20; i++) {
    new Thread(()->{
    System.out.println(HungerySingleton.getInstance());
    }).start();
    }
    }
    }
    2、懒汉式

    示例代码如下:

    /*
    懒汉模式
    1.线程安全性:多线程并发情况下不能保证实例对象的唯一性。
    2.性能:实现了懒加载,性能相对饿汉式比较好。
    */
    public class HoonSingleton {
    private static HoonSingleton instance = null;

    private HoonSingleton() {

    }

    // 在调用的过程中实例化对象并返回
    public static HoonSingleton getInstance() {
    if (null == instance) {
    instance = new HoonSingleton();
    }
    return instance;
    }

    public static void main(String[] args) {
    for (int i = 0; i < 20; i++) {
    new Thread(()->{
    System.out.println(HoonSingleton.getInstance());
    }).start();
    }
    }
    }
    3、懒汉式+同步方法

    示例代码如下:

    /*
    懒汉模式 + 同步方法
    1.线程安全性:通过增加synchronized保证了线程安全性。
    2.性能:使用synchronized使得程序退化到了串行执行,降低了性能。
    */
    public class HoonSingleton {
    private static HoonSingleton instance = null;

    private HoonSingleton() {

    }

    // 在调用的过程中实例化对象并返回(通过synchronized关键字修饰,保证线程安全性)
    public synchronized static HoonSingleton getInstance() {
    if (null == instance) {
    instance = new HoonSingleton();
    }
    return instance;
    }

    public static void main(String[] args) {
    for (int i = 0; i < 20; i++) {
    new Thread(()->{
    System.out.println(HoonSingleton.getInstance());
    }).start();
    }
    }
    }
    4、DCL(Double-Check-Locking):

    /*
    懒汉模式 + DCL
    1.线程安全性:通过synchronized以及DCL保证了线程安全性。
    2.性能:使用懒加载以及DCL,性能比较好。
    3.CPU在执行过程中有可能导致实例对象中的实例属性(对象)指令重排,引起空指针异常。
    /
    public class HoonSingleton {
    private static HoonSingleton instance = null;

    private HoonSingleton() {

    }

    // DCL(Double-check-locking)
    public static HoonSingleton getInstance() {
    // 通过synchronized以及两次判断(DCL)保证线程安全性
    if (null == instance) {
    synchronized (HoonSingleton.class) {
    if (null == instance) {
    instance = new HoonSingleton();
    }
    }
    }
    return instance;
    }

    public static void main(String[] args) {
    for (int i = 0; i < 20; i++) {
    new Thread(()->{
    System.out.println(HoonSingleton.getInstance());
    }).start();
    }
    }
    }
    通过volatile避免CPU指令重排导致空指针异常,进一步改良后的代码如下:

    /*
    懒汉模式 + DCL
    1.线程安全性:通过synchronized以及DCL保证了线程安全性。
    2.性能:使用懒加载以及DCL,性能比较好。
    */
    public class HoonSingleton {
    // 通过volatile避免CPU指令重排导致控制针异常
    private volatile static HoonSingleton instance = null;

    private HoonSingleton() {

    }

    // DCL(Double-check-locking)
    public static HoonSingleton getInstance() {
    // 通过synchronized以及两次判断(DCL)保证线程安全性
    if (null == instance) {
    synchronized (HoonSingleton.class) {
    if (null == instance) {
    instance = new HoonSingleton();
    }
    }
    }
    return instance;
    }

    public static void main(String[] args) {
    for (int i = 0; i < 20; i++) {
    new Thread(()->{
    System.out.println(HoonSingleton.getInstance());
    }).start();
    }
    }
    }
    5、Holder

    /*
    持有者模式(Holder)
    1.通过静态内部类实现懒加载,保证线程安全性,是目前应用比较广泛的一种单例模式
    /
    public class HolderDemo {

    private HolderDemo() {

    }

    private static class Holder {
    private static HolderDemo instance = new HolderDemo();
    }

    // 懒加载
    // synchronized
    //
    public static HolderDemo getInstance() {
    return Holder.instance;
    }
    }
    6、枚举式

    public enum EnumDemo {
    // 常量,在加载的时候被实例化,且只能实例化一次
    A, B, C, D;

    public static void m1() {
    System.out.println(“method”);
    }

    public static void main(String[] args) {
    A.m1();
    B.m1();
    C.m1();
    D.m1();
    System.out.println(A.getClass().getName());// 输出结果:EnumDemo
    System.out.println(B.getClass().getName());// 输出结果:EnumDemo
    System.out.println(C.getClass().getName());// 输出结果:EnumDemo
    System.out.println(D.getClass().getName());// 输出结果:EnumDemo
    }
    }
    改良代码:

    public enum EnumSingleton {
    INSTANCE;

    public static EnumSingleton getInstance() {
    return INSTANCE;
    }
    }
    改良

    /*
    同Holder(持有者模式)一样,是目前运用比较广泛的单例模式,大师结晶
    */
    public enum EnumSingletonDemo {

    private EnumSingletonDemo() {

    }

    private enum EnumHolder {
    INSTANCE;
    private EnumSingletonDemo instance;

    EnumHolder() {
    this.instance = new EnumSingletonDemo();
    }

    private EnumSingletonDemo getInstance() {
    return instance;
    }
    }


    public static EnumSingletonDemo getInstance() {
    return EnumHolder.INSTANCE.instance;
    }
    }