设计模式 - 单例模式 - Tips

为什么双重检查会带来空指针异常 问题?

java 复制代码
if (instance == null) {             
    synchronized (Singleton.class) {                                 
        if (instance == null) {                     
            instance = new Singleton();                 
        }             
    }         
}

instance = new Singleton();

上述加粗的代码并不是原子操作,包含三个步骤:

  1. 为 Singleton 分配内存地址

  2. 执行 Singleton() 构造方法,初始化成员变量等

  3. 将内存地址赋值给 instance 变量

假设线程 A 正在执行:

java 复制代码
instance = new Singleton();   

由于指令 **重排序,**线程 A 可能在构造函数执行之前,就已经将内存地址赋值给 instance,导致 instance 变为非 null。此时线程 B 会认为 instance 已经是合法对象,于是直接使用,结果可能:

  • 访问尚未初始化的字段

  • 抛出 NullPointerException

  • 出现逻辑错误或不可预知的行为

为什么可以通过 静态内部类 实现懒汉式 单例模式

java 复制代码
public class Singleton {     
    private Singleton() {}     
    
    private static class SingletonHolder {         
        private static final Singleton INSTANCE = new Singleton();     
    }        
    
    public static Singleton getInstance() {              
        return SingletonHolder.INSTANCE; 
    }  
}

这依赖于 Java 类加载机制的特性:

  • JVM 在加载外部类的过程中不会加载静态内部类,只有内部类的属性 / 方法被调用时才会进行加载(懒汉式

  • JVM 在加载类的时候会自动保证线程安全,一个类在 JVM 中只会被加载一次

相关推荐
程序_白白11 小时前
探讨一下java将来未来两年内的就业以及发展
java·开发语言
oak隔壁找我11 小时前
RabbitMQ 实现延迟通知的完整方案
java·后端
信码由缰11 小时前
Java的优势有哪些
java
WaWaJie_Ngen11 小时前
【设计模式】工厂模式(Factory)
c++·设计模式·简单工厂模式·工厂方法模式·抽象工厂模式
trow11 小时前
ConcurrentHashMap线程安全实现详解
java·后端
trow11 小时前
HashMap核心原理与源码剖析
java·后端
YuanlongWang11 小时前
C# 设计模式——工厂模式
开发语言·设计模式·c#
可观测性用观测云12 小时前
云原生架构下微服务接入 SkyWalking 最佳实践
java
消失的旧时光-194312 小时前
MQTT主题架构的艺术:从字符串拼接走向设计模式
设计模式
_殊途12 小时前
项目开发手册-开发流程
java