双重检查锁定与volatile关键字
在Java中,实现线程安全的延迟初始化单例通常采用双重检查锁定(Double-Checked Locking)模式。该模式通过同步块减少锁的粒度,提升性能,并使用volatile关键字防止指令重排序。示例代码如下:
public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}
此处volatile是关键,它确保多线程环境下实例的可见性,并避免因指令重排序导致的未初始化对象被引用。
静态内部类实现
利用JVM类加载机制,静态内部类实现单例无需同步锁,既实现延迟加载又保证线程安全。代码如下:
public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; }}
该方式在类加载时不会初始化INSTANCE,只有在调用getInstance()时才会加载SingletonHolder类并创建实例,兼具简洁性与高效性。
枚举单例与序列化安全
枚举类型是实现单例的最佳实践之一,能天然防止反射攻击和序列化破坏。示例:
public enum EnumSingleton { INSTANCE; public void doSomething() { // 业务方法 }}
枚举单例由JVM保证全局唯一,且序列化时仅会输出枚举名称,反序列化时通过valueOf方法匹配现有实例,避免创建新对象。
防止反射与克隆破坏
除枚举外,其他实现需额外防护。可在私有构造器中添加防止反射重复调用的逻辑,并重写clone方法:
private Singleton() { if (instance != null) { throw new IllegalStateException(Already initialized); }}@Overrideprotected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException();}
单例模式的适用场景与注意事项
单例适用于需要全局唯一组件的场景,如配置管理、线程池或连接池。但需注意:
- 单例可能导致代码耦合度高,不利于单元测试
- 在分布式系统中需改用分布式锁或依赖容器管理实例
- 避免在单例中保存可能导致内存泄漏的上下文数据