我来详细介绍一下 Java 中的单例模式。单例模式确保一个类只有一个实例,并提供一个全局访问点。
1. 饿汉式(线程安全)
public class EagerSingleton {
// 类加载时就创建实例
private static final EagerSingleton instance = new EagerSingleton();
// 私有构造函数
private EagerSingleton() {
// 防止反射创建实例
if (instance != null) {
throw new RuntimeException("单例模式不允许创建多个实例");
}
}
// 全局访问点
public static EagerSingleton getInstance() {
return instance;
}
}
2. 懒汉式(线程不安全)
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
3. 懒汉式(线程安全 - 同步方法)
public class SynchronizedSingleton {
private static SynchronizedSingleton instance;
private SynchronizedSingleton() {}
// 使用synchronized保证线程安全,但性能较低
public static synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
}
4. 双重检查锁定(DCL)
public class DoubleCheckedLockingSingleton {
// 使用volatile防止指令重排序
private static volatile DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {}
public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) { // 第二次检查
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
5. 静态内部类(推荐使用)
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {}
// 静态内部类在第一次被引用时才会加载
private static class SingletonHolder {
private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.instance;
}
}
6. 枚举单例(最佳实践)
public enum EnumSingleton {
INSTANCE;
// 可以添加其他方法
public void doSomething() {
System.out.println("枚举单例方法执行");
}
}
// 使用方式
EnumSingleton.INSTANCE.doSomething();
7. 防止反射和反序列化破坏单例
import java.io.Serializable;
import java.lang.reflect.Constructor;
public class PerfectSingleton implements Serializable {
private static final long serialVersionUID = 1L;
private static volatile PerfectSingleton instance;
private static boolean flag = false;
private PerfectSingleton() {
// 防止反射攻击
synchronized (PerfectSingleton.class) {
if (flag) {
throw new RuntimeException("不能通过反射创建多个实例");
}
flag = true;
}
}
public static PerfectSingleton getInstance() {
if (instance == null) {
synchronized (PerfectSingleton.class) {
if (instance == null) {
instance = new PerfectSingleton();
}
}
}
return instance;
}
// 防止反序列化创建新实例
private Object readResolve() {
return getInstance();
}
}
测试代码
public class SingletonTest {
public static void main(String[] args) {
// 测试饿汉式
EagerSingleton eager1 = EagerSingleton.getInstance();
EagerSingleton eager2 = EagerSingleton.getInstance();
System.out.println("饿汉式单例: " + (eager1 == eager2)); // true
// 测试枚举单例
EnumSingleton enum1 = EnumSingleton.INSTANCE;
EnumSingleton enum2 = EnumSingleton.INSTANCE;
System.out.println("枚举单例: " + (enum1 == enum2)); // true
// 测试静态内部类单例
StaticInnerClassSingleton inner1 = StaticInnerClassSingleton.getInstance();
StaticInnerClassSingleton inner2 = StaticInnerClassSingleton.getInstance();
System.out.println("静态内部类单例: " + (inner1 == inner2)); // true
}
}
各种实现方式的比较
实现方式 | 线程安全 | 懒加载 | 性能 | 防止反射 | 防止反序列化 |
---|---|---|---|---|---|
饿汉式 | ✅ | ❌ | 高 | ❌ | ❌ |
懒汉式(同步) | ✅ | ✅ | 低 | ❌ | ❌ |
双重检查锁定 | ✅ | ✅ | 中 | ❌ | ❌ |
静态内部类 | ✅ | ✅ | 高 | ❌ | ❌ |
枚举 | ✅ | ❌ | 高 | ✅ | ✅ |
总结
- 推荐使用:枚举单例或静态内部类单例
- 需要懒加载:静态内部类单例
- 需要最高安全性:枚举单例(天然防止反射和序列化攻击)
- 在旧版本Java中:双重检查锁定或静态内部类
单例模式适用于需要全局唯一实例的场景,如配置管理、连接池、日志记录器等。