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驱动无法加载错误解决方法_驱动签名验证失败处理步骤


