1. 饿汉式单例模式
public class HungrySingleton {
private static final HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return instance;
}
}
- 线程安全性:饿汉式在类加载时就创建实例,类加载过程由 JVM 保证线程安全,所以饿汉式天然线程安全。
- 优点:实现简单,线程安全。
- 缺点:如果实例化过程耗时较长,可能影响类加载速度,且不管是否使用该实例,都会在类加载时创建,浪费内存。
2. 懒汉式(线程不安全)
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
- 线程安全性:这种方式在多线程环境下,多个线程可能同时进入
if (instance == null)
判断,导致创建多个实例,所以线程不安全。
- 优点:延迟加载,只有在调用
getInstance
方法时才创建实例。
- 缺点:线程不安全,不能在多线程环境下使用。
3. 懒汉式(线程安全 - 同步方法)
public class ThreadSafeLazySingleton {
private static ThreadSafeLazySingleton instance;
private ThreadSafeLazySingleton() {}
public static synchronized ThreadSafeLazySingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeLazySingleton();
}
return instance;
}
}
- 线程安全性:通过
synchronized
关键字修饰 getInstance
方法,保证同一时间只有一个线程能进入该方法,从而确保线程安全。
- 优点:实现简单,保证线程安全且延迟加载。
- 缺点:由于
synchronized
修饰整个方法,性能较低,每次调用 getInstance
方法都需要获取锁。
4. 双重检查锁定(DCL)
public class DCLSingleton {
private volatile static DCLSingleton instance;
private DCLSingleton() {}
public static DCLSingleton getInstance() {
if (instance == null) {
synchronized (DCLSingleton.class) {
if (instance == null) {
instance = new DCLSingleton();
}
}
}
return instance;
}
}
- 线程安全性:
volatile
关键字禁止指令重排,防止在实例化过程中,对象尚未完全初始化就被其他线程访问。第一次 if (instance == null)
检查是为了避免不必要的同步,第二次 if (instance == null)
检查是在获取锁后,确保只有一个线程创建实例,从而保证线程安全。
- 优点:延迟加载,性能较高,只有第一次创建实例时需要同步。
- 缺点:实现相对复杂,需要正确使用
volatile
关键字。
5. 静态内部类
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
private static class InnerClass {
private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return InnerClass.instance;
}
}
- 线程安全性:静态内部类只有在调用
getInstance
方法时才会加载,类加载过程由 JVM 保证线程安全,所以线程安全。
- 优点:延迟加载,实现相对简单,性能较好。
- 缺点:与饿汉式相比,理解起来稍复杂一些。