2024.10.11 | cuithink | 2099次围观
4. 单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一种全局访问点以访问该实例
饿汉式和懒汉式的区别
初始化时机不同:饿汉式单例模式在类加载时就立即初始化并创建单例对象,而懒汉式单例模式则是在第一次使用时才会进行初始化,并创建单例对象。
线程安全性不同:饿汉式单例模式在类加载时就创建了单例对象,因此天生就是线程安全的。而懒汉式单例模式在第一次使用时才会创建单例对象,如果多个线程同时调用getInstance()方法,可能会创建出多个单例对象,因此需要进行同步控制来保证线程安全。
内存占用不同:饿汉式单例模式在类加载时就创建了单例对象,因此占用的内存较多。而懒汉式单例模式在第一次使用时才会创建单例对象,因此占用的内存相对较少。
实现方式

饿汉式
class Singleton {
// 1. 加载该类时,单例就会自动被创建
private static Singleton ourInstance = new Singleton();
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 通过调用静态方法获得创建的单例
public static Singleton newInstance() {
return ourInstance;
}
}懒汉式
class Singleton {
private static Singleton ourInstance = null;
private Singleton() {
}
public static Singleton newInstance() {
// 加入双重校验锁
// 校验锁1:第1个if
if( ourInstance == null){ // ①
synchronized (Singleton.class){ // ②
// 校验锁2:第2个 if
if( ourInstance == null){
ourInstance = new Singleton();
}
}
}
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 判断 = 为空(单例已创建),因此也不会创建多余的实例
静态内部类
原理 根据 静态内部类 的特性(外部类的加载不影响内部类),同时解决了按
需加载、线程安全的问题,同时实现简洁
1. 在静态内部类里创建单例,在装载该内部类时才会去实例化单例
2. 线程安全:类是由 JVM 加载,而 JVM 只会加载1遍,保证只有1个单例
枚举
因为枚举类型是线程安全的,并且只会装载一次,设计者充分的利用了枚
举的这个特性来实现单例模式,枚举的写法非常简单,而且枚举类型是所
用单例实现中唯一一种不会被破坏的单例实现模式。
为什么枚举类可以阻止反射的破坏?
首先枚举类中是没有空参构造方法的,只有一个带两个参数的构造方法 真正原因是: 反射方法中不予许使用反射创建枚举对象
粤ICP备16076548号
