传奇绳索蜘蛛侠
150.20MB · 2025-11-18
单例模式的核心设计初衷是确保一个类在整个应用程序中只有一个实例,并提供一个全局访问点
该设计模式主要解决以下问题:
new键字创建实例单例模式是一种简单的设计模式,因此只涉及一个角色:
public class Singleton {
// 唯一实例,类加载时初始化
private static final Singleton instance = new Singleton();
// 私有构造方法,防止外部实例化
private Singleton() {}
// 提供全局访问点,返回唯一实例
public static Singleton getInstance() {
// 返回唯一实例
return instance;
}
}
public class Singleton {
// 唯一实例,延迟初始化
private static Singleton instance;
// 私有构造方法,防止外部实例化
private Singleton() {}
// 提供全局访问点,返回唯一实例
public static Singleton getInstance() {
// 如果实例为空,创建新实例
if (instance == null) {
instance = new Singleton();
}
// 返回唯一实例
return instance;
}
}
instance == null的判断条件,导致创建多个实例比如像这样:
static void checkMultiThread() {
for(int i = 0; i < 100; i ++) {
new Thread(() -> {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Singleton instance = Singleton.getInstance();
System.out.println(Thread.currentThread().getName() + ": " + instance);
}).start();
}
}
public class Singleton {
// 唯一实例,延迟初始化
private static Singleton instance;
// 私有构造方法,防止外部实例化
private Singleton() {}
// 提供全局访问点,返回唯一实例
// 同步方法,确保线程安全
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
synchronized关键字保证线程安全synchronized在方法级别使用,相当于对整个类对象加锁
getInstance()方法都需要先获取锁其实只是在第一次创建实例时才需要同步,因此造成了大量不必要的同步开销
在高并发的场景下,会竞争锁,未获取到锁的会被阻塞等待,而相应的线程的阻塞和唤醒会带来上下文切换的开销
public class Singleton {
// 唯一实例,延迟初始化 volatile 确保可见性
private volatile static Singleton instance;
// 私有构造方法,防止外部实例化
private Singleton() {}
// 提供全局访问点,返回唯一实例
public static Singleton getInstance() {
// 第一次检查,避免不必要的同步
if (instance == null) {
synchronized (Singleton.class) {
// 第二次检查,确保线程安全
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
volatile关键字必不可少,防止指令重排序public class Singleton {
// 私有构造方法,防止外部实例化
private Singleton() {}
// 静态内部类,延迟初始化唯一实例
private static class SingletonHolder {
// 唯一实例,延迟初始化
private static final Singleton INSTANCE = new Singleton();
}
// 提供全局访问点,返回唯一实例
public static Singleton getInstance() {
// 返回唯一实例
return SingletonHolder.INSTANCE;
}
}
volatile关键字的作用
instance = new Singleton()这行代码在多线程环境下的执行顺序问题双重检查的工作流程
①第一次检查 :所有线程都会先检查instance == null
instance != null ),直接返回实例,无需同步,这是性能优化的关键②同步代码块 :多个线程竞争锁,只有一个线程能进入
instance == null )③后续调用 :实例创建完成后,所有后续调用只需通过第一次检查,直接返回实例,无需同步
enum Singleton {
INSTANCE;
// 可以添加成员方法
public void doSomething() {
// 实现功能
}
}
很大程度上是 JVM 本身对其的保证
readResolve()方法,确保反序列化时返回同一个实例单例模式是Java中使用频率最高的设计模式之一,理解其设计思想和实现方式对于编写高质量的Java程序至关重要
在实际开发中,应根据具体需求选择合适的实现方式,平衡线程安全性、性能和资源占用等因素