设计模式 - 单例模式 - 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 中只会被加载一次

相关推荐
程序员小假9 小时前
我们来说一下无锁队列 Disruptor 的原理
java·后端
资生算法程序员_畅想家_剑魔9 小时前
Kotlin常见技术分享-02-相对于Java 的核心优势-协程
java·开发语言·kotlin
ProgramHan9 小时前
Spring Boot 3.2 新特性:虚拟线程的落地实践
java·jvm·spring boot
nbsaas-boot10 小时前
Go vs Java 的三阶段切换路线图
java·开发语言·golang
毕设源码-钟学长10 小时前
【开题答辩全过程】以 基于Java的慕课点评网站为例,包含答辩的问题和答案
java·开发语言
小北方城市网10 小时前
分布式锁实战指南:从选型到落地,避开 90% 的坑
java·数据库·redis·分布式·python·缓存
深圳佛手11 小时前
使用java,怎么样高效地读取一个大文件(10g以上)?
java·开发语言
sheji341611 小时前
【开题答辩全过程】以 景点移动导游系统的设计与实现为例,包含答辩的问题和答案
java
毕设源码-赖学姐11 小时前
【开题答辩全过程】以 高校失物招领信息管理系统的设计与开发为例,包含答辩的问题和答案
java
xiaolyuh12311 小时前
【XXL-JOB】 GLUE模式 底层实现原理
java·开发语言·前端·python·xxl-job