Java面试——单例模式的多种实现与线程安全

发布时间 - 2026-01-30 00:00:00    点击率:
饿汉式天生线程安全,因static字段在类加载时由JVM串行初始化;DCL必须用volatile禁止重排序;枚举单例由JVM保障原子性、防反射和反序列化;静态内部类实现懒加载但可能被间接引用提前触发。

饿汉式为什么天生线程安全

因为 static 字段在类加载阶段就完成初始化,而类加载由 JVM 保证串行执行,不存在竞态条件。只要不手动调用 Class.forName(...) 触发多次加载(正常情况不会),实例就唯一且立即可用。

但要注意:即使没用到该单例,类一加载就会创建实例,可能浪费资源;也无法传递构造参数(除非改用静态代码块 + 私有构造器传参)。

public class SingletonEager {
    private static final SingletonEager instance = new SingletonEager();

    private SingletonEager() {}

    public static SingletonEager getInstance() {
        return instance;
    }
}

双重检查锁(DCL)必须加 volatile

不加 volatile 会导致指令重排序:JVM 可能将 new SingletonLazy() 拆成「分配内存→设置引用→调用构造器」三步,而「设置引用」可能早于「构造器执行完毕」。其他线程看到非 null 的 instance,却访问到未初始化完成的对象,引发 NullPointerException 或状态不一致。

  • volatile 禁止重排序,并保证可见性
  • 第一次判空避免每次同步开销;第二次判空防止多线程重复初始化
  • 同步块必须锁定 SingletonLazy.class 或当前类的 Class 对象,不能锁 this(此时对象还没造出来)
public class SingletonLazy {
    private static volatile SingletonLazy instance;

    private SingletonLazy() {}

    public static SingletonLazy getInstance() {
        if (instance == null) {
            synchronized (SingletonLazy.class) {
                if (instance == null) {
                    instance = new SingletonLazy();
                }
            }
        }
        return

instance; } }

枚举单例为何最简且防反射/反序列化攻击

JVM 保证枚举类型的实例创建是原子的、线程安全的,且天然防止反射调用私有构造器(Enum 的构造器被 JVM 特殊保护)、也自动阻止反序列化生成新实例(readObject 被禁用)。

立即学习“Java免费学习笔记(深入)”;

它不是“语法糖”,而是 JVM 层级的保障。如果面试官问“还能怎么破坏枚举单例”,答案基本只有:修改字节码或用 Unsafe 绕过(超出常规 Java 范畴)。

public enum SingletonEnum {
    INSTANCE;

    public void doSomething() {
        // ...
    }
}

静态内部类方式的隐含限制

利用类加载机制延迟初始化:外部类加载时,静态内部类不加载;只有首次调用 getInstance() 时,JVM 才加载并初始化 Holder 类,从而创建实例。线程安全、懒加载、无同步开销。

但要注意:如果外部类中其他静态字段或静态代码块触发了 Holder 类的间接引用(比如通过反射访问其 class 对象),可能导致提前初始化——这种情况极少见,但一旦发生,就破坏了“懒”的语义。

public class SingletonStaticInner {
    private SingletonStaticInner() {}

    private static class Holder {
        private static final SingletonStaticInner INSTANCE = new SingletonStaticInner();
    }

    public static SingletonStaticInner getInstance() {
        return Holder.INSTANCE;
    }
}
真正容易被忽略的,是 DCL 中 volatile 的必要性,以及枚举单例在反序列化场景下无需额外实现 readResolve —— 这两点在高并发或分布式序列化场景里,往往决定单例是否真的“唯一”。


# java  # 字节  # 懒加载  # 一加  # 为什么  # 分布式  # jvm  # Static  # NULL  # 枚举类型  # enum  # volatile  # class  # 线程  # 多线程  # 并发  # 对象  # this  # 加载  # 序列化  # 化生  # 但要  # 就会  # 还没  # 首次  # 还能  # 不存在  # 这种情况 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何自己制作一个网站链接,如何制作一个企业网站,建设网站的基本步骤有哪些?  利用 Google AI 进行 YouTube 视频 SEO 描述优化  利用python获取某年中每个月的第一天和最后一天  Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面  魔方云NAT建站如何实现端口转发?  Laravel怎么使用Session存储数据_Laravel会话管理与自定义驱动配置【详解】  微信小程序 wx.uploadFile无法上传解决办法  Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧  如何用免费手机建站系统零基础打造专业网站?  如何快速查询域名建站关键信息?  google浏览器怎么清理缓存_谷歌浏览器清除缓存加速详细步骤  标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南  Android实现代码画虚线边框背景效果  Laravel如何实现数据导出到CSV文件_Laravel原生流式输出大数据量CSV【方案】  Laravel Seeder填充数据教程_Laravel模型工厂Factory使用  Laravel怎么进行数据库回滚_Laravel Migration数据库版本控制与回滚操作  Laravel如何使用Guzzle调用外部接口_Laravel发起HTTP请求与JSON数据解析【详解】  网站制作壁纸教程视频,电脑壁纸网站?  专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?  详解Huffman编码算法之Java实现  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用  黑客入侵网站服务器的常见手法有哪些?  东莞市网站制作公司有哪些,东莞找工作用什么网站好?  Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】  网站建设整体流程解析,建站其实很容易!  如何用西部建站助手快速创建专业网站?  高防服务器租用指南:配置选择与快速部署攻略  如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?  如何解决hover在ie6中的兼容性问题  javascript基本数据类型及类型检测常用方法小结  再谈Python中的字符串与字符编码(推荐)  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  Laravel如何实现数据库事务?(DB Facade示例)  Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲  免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?  Laravel如何记录日志_Laravel Logging系统配置与自定义日志通道  如何在阿里云香港服务器快速搭建网站?  php485函数参数是什么意思_php485各参数详细说明【介绍】  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  如何用AWS免费套餐快速搭建高效网站?  Swift开发中switch语句值绑定模式  Laravel如何配置Horizon来管理队列?(安装和使用)  phpredis提高消息队列的实时性方法(推荐)  作用域操作符会触发自动加载吗_php类自动加载机制与::调用【教程】  Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出  简历没回改:利用AI润色让你的文字更专业  Win11怎么查看显卡温度 Win11任务管理器查看GPU温度【技巧】  Laravel如何使用withoutEvents方法临时禁用模型事件  Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤