写一个singleton出来 深入解析单例模式:确保类唯一实例及全局访问点的实现要点

网安智编 厦门萤点网络科技 2025-08-10 00:05 99 0
单例模式( )是设计模式中最基础也最常用的一种。它的核心目标非常明确:确保一个类在任何情况下都只有一个实例存在,并且提供一个全局唯一的访问点来获取这个实例。 为什么需要单例? 想象一下日志记录器、配置管理、线程池、数据库连接池等场景,通常我...

单例模式( )是设计模式中最基础也最常用的一种。它的核心目标非常明确:确保一个类在任何情况下都只有一个实例存在,并且提供一个全局唯一的访问点来获取这个实例。

为什么需要单例? 想象一下日志记录器、配置管理、线程池、数据库连接池等场景,通常我们希望这些资源在整个应用中是唯一的,避免不必要的开销和冲突。单例模式正是解决这类需求的利器。

实现单例模式的关键点:

私有化构造方法: 这是防止外部随意创建新实例的第一道屏障。内部持有私有静态实例: 这个静态变量负责保存那个唯一的实例。提供公共静态访问方法: 这是外部获取唯一实例的唯一入口。

接下来,我们详细探讨Java中实现单例模式的6种经典方式,分析它们的原理、优缺点和适用场景。

1. 懒汉式 (Lazy - 线程安全版)

public class SingletonLazy {
    private static SingletonLazy instance; // 私有静态变量,保存唯一实例
    // 私有构造函数,防止外部new
    private SingletonLazy() {
        // 初始化代码...
    }
    // 公共静态方法,获取唯一实例(同步方法保证线程安全)
    public static synchronized SingletonLazy getInstance() {
        if (instance == null) { // 第一次调用时创建
            instance = new SingletonLazy();
        }
        return instance;
    }
}

2. 双重检查锁 (- - DCL)

public class SingletonDCL {
    // 关键:volatile确保多线程环境下的可见性和有序性
    private static volatile SingletonDCL instance;
    private SingletonDCL() {
    }
    public static SingletonDCL getInstance() {
        if (instance == null) { // 第一次检查 (无锁,快速判断)
            synchronized (SingletonDCL.class) { // 加锁
                if (instance == null) { // 第二次检查 (加锁后,确保只有一个线程进入创建)
                    instance = new SingletonDCL(); // volatile防止此处指令重排序
                }
            }
        }
        return instance;
    }
}

3. 饿汉式 (Eager )

public class SingletonEager {
    // 类加载时直接初始化(JVM保证线程安全)
    private static final SingletonEager INSTANCE = new SingletonEager();
    private SingletonEager() {
    }
    public static SingletonEager getInstance() {
        return INSTANCE; // 直接返回已创建好的实例
    }
}

4. 静态代码块饿汉式 ( Block Eager)

Java单例模式6种方法_单例模式实现方式_写一个singleton出来

public class SingletonStaticBlock {
    private static final SingletonStaticBlock INSTANCE;
    // 静态代码块初始化(类加载时执行,JVM保证线程安全)
    static {
        try {
            INSTANCE = new SingletonStaticBlock();
            // 可以在这里执行更复杂的初始化逻辑
        } catch (Exception e) {
            throw new RuntimeException("创建单例失败", e);
        }
    }
    private SingletonStaticBlock() {
    }
    public static SingletonStaticBlock getInstance() {
        return INSTANCE;
    }
}

5. 静态内部类 ( Inner Class / )

public class SingletonHolder {
    private SingletonHolder() {
    }
    // 私有静态内部类,持有单例实例
    private static class Holder {
        // JVM在加载Holder类时初始化INSTANCE(线程安全)
        private static final SingletonHolder INSTANCE = new SingletonHolder();
    }
    public static SingletonHolder getInstance() {
        return Holder.INSTANCE; // 首次调用时触发Holder类加载和INSTANCE初始化
    }
}

6. 枚举 (Enum)缺点: 枚举特性是Java 5引入的。写法与传统类稍有不同,部分开发者可能不习惯。无法继承其他类(枚举本身已继承java.lang.Enum)。《 Java》作者 Bloch强力推荐的方式。

public enum SingletonEnum {
    INSTANCE; // 唯一的枚举常量,即单例实例
    // 可以添加实例方法
    public void doSomething() {
        // 业务逻辑...
        System.out.println("SingletonEnum instance is working!");
    }
}
// 使用方式:
SingletonEnum instance = SingletonEnum.INSTANCE;
instance.doSomething();

总结与选择建议

单例模式虽好,但也要注意:

理解这6种实现方式及其背后的原理,能帮助你在实际开发中根据具体需求(性能、延迟加载、安全性要求等)选择最合适的单例模式实现。

你平时最喜欢用哪种方式实现单例呢?或者在实际项目中遇到过哪些单例相关的“坑”?欢迎在评论区留言讨论!