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

相关推荐
kyle~1 分钟前
C++---初始化列表(initializer_list)
java·c++·list
命苦的孩子4 分钟前
Java 数学工具类 Math
java·开发语言
练习时长两年半的程序员小胡12 分钟前
JVM 垃圾回收机制全景解析:从对象回收到收集算法
java·jvm·算法·垃圾回收
笑衬人心。16 分钟前
JVM 笔记:类加载、内存管理、垃圾收集与垃圾收集器
java·jvm·笔记
程序猿小D19 分钟前
Java项目:基于SSM框架实现的进销存管理系统【ssm+B/S架构+源码+数据库+毕业论文+远程部署】
java·数据库·mysql·ssm·jsp·毕业论文·进销存管理系统
得物技术25 分钟前
Java volatile 关键字到底是什么|得物技术
java·后端
HoHeHa27 分钟前
IDEA 手动下载安装数据库驱动,IDEA无法下载数据库驱动问题解决方案,IDEA无法连接数据库解决方案(通用,Oracle为例)
java·数据库·intellij-idea
你可以叫我仔哥呀32 分钟前
Java程序员学从0学AI(七)
java·开发语言·人工智能·ai·spring ai
杨DaB1 小时前
【SpringMVC】MVC中Controller的配置 、RestFul的使用、页面重定向和转发
java·笔记·后端·学习·spring·mvc·restful
linyb极客之路1 小时前
干货来袭!5 分钟学会快速实现责任链,效率直接拉满!
java