Java 单例模式 复习

123 阅读2分钟

Java 设计模式 单例模式

单例模式代码复习

单例模式是常用设计模式之一,本文简单讲解常用的集中Java单例模式实现

1.饿汉式 - 线程安全 (不推荐使用)
2.懒汉式 - 线程非安全 (多线程禁止使用)
3.懒汉式 - 线程安全
4.静态内部类 - 线程安全
5.枚举 - 线程安全 (最佳)

饿汉式 - 线程安全
主要是利用static类型成员变量在类加载-初始化时,由JVM保证了线程安全
思想是空间换时间,Singleton类只要被加载就会导致单例产生

// 单例模式 饿汉式 线程安全
class Singleton {
    // 利用Java底层加载类时初始化必保证线程安全特性初始化单例
    private static Singleton singleton = new Singleton();

    // 私有化构造方法
    private Singleton() {}

    // 返回单例
    public static Singleton getInstance() {
        return singleton;
    }
}

懒汉式 - 线程非安全 (多线程禁止使用)
不做讲解,不推荐使用

// 单例模式 懒汉式 线程不安全
class Singleton {
    private static Singleton instance = null;
    
    private Singleton(){}
    
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

懒汉式-双重锁校验 - 线程安全
思想是时间换空间
static单例用volatile修饰是保证多线程代码执行有序性
在instance = new Single()时如果instance没有用volatile修饰,则有可能导致其他代码进入getInstance时判断非空不成立,直接返回instance,而此时instance实际为null

// 单例模式 懒汉式-双重锁校验 线程安全
class Singleton {
    // volatile保证创建对象的有序性
    private volatile static Singleton instance = null;

    private Singleton(){}

    public static Singleton getInstance() {
        // 双重锁校验
        if(instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

静态内部类-延迟加载 线程安全
当getInstance方法第一次被执行的时候
它第一次读取内部静态类SingletonHelper.instance
此时SingletonHelper类得到初始化
而这个类在装载并被初始化的时候 会初始化它的静态域,从而创建Singleton的实例
由于是静态的域
因此只会在虚拟机装载类的时候初始化一次
并由JVM来保证新车安全

// 单例模式 静态内部类 线程安全
class Singleton {

    // 私有化构造方法
    private Singleton() {}

    // 只有当内部类被使用时才会加载
    private static class SingletonHelper {
        private static Singleton singleton = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHelper.singleton;
    }

}

枚举 线程安全

// 单例模式 枚举实现 线程安全
enum Singleton {
    INSTANCE;

    public void function() {
        // TODO
    }
}

总结:
以上就是常用的Java单例模式代码实现方式,各有优劣势
比较重要的是需要搞清楚懒汉式-双重锁校验的原理和为何需要使用volatile关键字