0

0

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

煙雲

煙雲

发布时间:2026-01-30 08:19:02

|

315人浏览过

|

来源于php中文网

原创

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

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

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

因为 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免费学习笔记(深入)”;

BJXSHOP网上开店专家
BJXSHOP网上开店专家

BJXShop网上购物系统是一个高效、稳定、安全的电子商店销售平台,经过近三年市场的考验,在中国网购系统中属领先水平;完善的订单管理、销售统计系统;网站模版可DIY、亦可导入导出;会员、商品种类和价格均实现无限等级;管理员权限可细分;整合了多种在线支付接口;强有力搜索引擎支持... 程序更新:此版本是伴江行官方商业版程序,已经终止销售,现于免费给大家使用。比其以前的免费版功能增加了:1,整合了论坛

下载

它不是“语法糖”,而是 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 —— 这两点在高并发或分布式序列化场景里,往往决定单例是否真的“唯一”。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

330

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

235

2023.10.07

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

237

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

458

2024.03.01

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

69

2025.10.23

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

469

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.12.06

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

523

2023.08.10

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

9

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3万人学习

C# 教程
C# 教程

共94课时 | 7.9万人学习

Java 教程
Java 教程

共578课时 | 53.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号