java单例模式中,static通过类加载机制保证线程安全:饿汉式在类加载时初始化,静态内部类延迟至首次访问holder.instance时初始化,static块则确保多步初始化的原子性。

Java中用static实现单例模式,核心在于借助类加载机制的“一次性”特性,配合私有构造与静态成员控制实例唯一性。关键不在于加锁有多严,而在于让JVM保证静态初始化只发生一次。
饿汉式:靠类加载时机天然线程安全
静态变量在类加载时就完成初始化,而JVM规范明确要求类加载过程是线程安全的——多个线程同时触发加载,只会执行一次静态初始化。
- 写法:直接在声明静态变量时new出实例,如private static final Singleton instance = new Singleton();
- 优点:无同步开销,天生线程安全,获取实例快
- 缺点:类一加载就创建对象,即使从未调用getInstance(),存在内存浪费风险
懒汉式(synchronized方法):用类锁兜底
把实例创建延迟到第一次调用getInstance(),但必须防止多线程并发创建。synchronized修饰静态方法,等价于锁住Class对象,确保同一时刻只有一个线程进入。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 写法:public static synchronized Singleton getInstance(),内部判空+new
- 注意:虽然安全,但每次调用都需获取类锁,高并发下成为性能瓶颈
- 本质:用JVM提供的类级互斥机制,弥补了“延迟初始化”带来的竞态风险
静态内部类:兼顾懒加载与线程安全的优选方案
利用JVM对静态内部类的加载规则——只有首次访问其静态成员时才触发初始化,且该过程由JVM保障单次性。
- 写法:定义一个static class Holder { static final Singleton INSTANCE = new Singleton(); },getInstance()中返回Holder.INSTANCE
- 优势:既不提前占用资源,又无需显式同步;加载时机由JVM控制,比手动加锁更轻量可靠
- 原理:外部类加载时,内部类不会被加载;只有调用getInstance()访问Holder.INSTANCE时,JVM才去加载Holder并执行其静态初始化
为什么static块也安全?因为类初始化是原子操作
哪怕代码里写了多个static块,JVM在类首次主动使用时,会按顺序执行全部static块,且整个过程不可中断、不可重入。
- 两个线程同时发现类未初始化,JVM内部会协调,仅允许一个线程执行初始化流程,另一个阻塞等待
- 这意味着:用static块赋值instance,和用static变量直接初始化,在线程安全性上等价
- 但static块更适合需要多步逻辑的初始化(如读配置、建连接),而不仅是new对象
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










