小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2025-10-11 / 0 阅读
0
0

Java 中的单例模式

我来详细介绍一下 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中:双重检查锁定或静态内部类

单例模式适用于需要全局唯一实例的场景,如配置管理、连接池、日志记录器等。


评论