1. 抛出问题, 先代码实现(非设计模式方式)

2. 具体设计模式说明和解释(生活应用场景)

项目中读取文件的类, 做数据库连接的类

3. 代码实现

饿汉式 :个人推荐, 简单, 安全.

这种方式可以保证线程安全(因为类加载时, 直接创建了实例, JVM 可以保证这个实例是线程安全的, 所以getInstance不需要synchronized)

package com.leon.design;

public class SingletonDemo {

    public static void main(String[] args) {
        SingletonHungry s1 = SingletonHungry.getInstance();
        SingletonHungry s2 = SingletonHungry.getInstance();
        System.out.println(s1.equals(s2));
    }
}

class SingletonHungry {
    private static SingletonHungry instance = new SingletonHungry();
    
    private SingletonHungry() {};
    
    public static SingletonHungry getInstance() {
        return instance;
    }

}

懒汉式 : 不推荐

package com.leon.design;

import java.lang.reflect.Constructor;

public class SingletonDemo2 {

    public static void main(String[] args) throws Exception {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1.equals(s2));
    }
}

class SingletonLazy {
    private static SingletonLazy instance;
    
    private SingletonLazy() {};
    
    public static synchronized SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}

静态内部类: 类似饿汉式

package com.leon.design;

import java.lang.reflect.Constructor;

public class SingletonDemo3 {

    public static void main(String[] args) throws Exception {
        SingletonLazy s1 = SingletonLazy.getInstance();
        SingletonLazy s2 = SingletonLazy.getInstance();
        System.out.println(s1.equals(s2));
    }
}

class SingletonStatic {
    
    // 内部类加载(也相当于类加载时) 创建的对象, 所以是线程安全的
    private static class SingletonStaticInner {
        private static final SingletonStatic instance = new SingletonStatic();
    }
    
    public static SingletonStatic getInstance() {
        return SingletonStaticInner.instance;
    }
    
    private SingletonStatic() {};
}

枚举: 

package com.leon.design;

import java.lang.reflect.Constructor;

public class SingletonDemo4 {

    public static void main(String[] args) throws Exception {
        SingletonEnum s1 = SingletonEnum.INSTANCE;
        SingletonEnum s2 = SingletonEnum.INSTANCE;
        System.out.println(s1.equals(s2));
        s1.otherFunction();
    }
}

// 因为枚举本事是单例的, 所以可以直接使用 INSTANCE
enum SingletonEnum {
    INSTANCE;
    
    public void otherFunction() {
        System.out.println("others");
    };
}

4. UML图 (原理与角色)

5. 具体源码应用 & 分析

JDK 中的 RUNTime 类 -> 用的是 饿汉式 方式.

应用场景:

需要频繁进行创建 / 销毁的对象

创建对象时消耗过多的资源, 但又经常用到的对象,工具类对象,频繁访问数据库/文件的对象.