讲师中心 微信公众号
AI工具推荐 视频效率加速

Java中单例的用法_Java中单例模式的实现

胖枫酱_1676

胖枫酱_1676

发布时间:2025-06-19 08:42:04

|

510人浏览过

|

来源于php中文网

原创

单例模式确保一个类在整个应用程序中只有一个实例存在。其核心实现方式包括:1.饿汉式在类加载时初始化,线程安全但可能浪费资源;2.懒汉式延迟加载但需同步机制影响性能;3.dcl通过双重校验锁和volatile关键字优化线程安全与性能;4.静态内部类利用类加载机制实现延迟加载和线程安全;5.枚举天然支持线程安全、防止反射和序列化攻击但无法延迟加载。为保证线程安全,dcl需使用volatile防止指令重排序,而饿汉式、静态内部类和枚举本身依赖类加载机制保障安全。防止反射攻击可通过构造函数检查实例或使用枚举实现;防止序列化攻击则通过readresolve方法返回已有实例或使用枚举。单例优点包括节省资源、提供全局访问点和延迟加载,缺点涉及隐藏依赖、测试困难及多线程下的复杂性。适用场景如数据库连接池、配置管理、线程池等,具体实现应根据需求选择。

Java中单例的用法_Java中单例模式的实现

单例模式,简单来说,就是确保一个类在整个应用程序中只有一个实例存在。这在某些场景下非常有用,比如管理数据库连接池、配置信息或者线程池等资源,避免重复创建带来的资源浪费和状态不一致问题。

Java中单例的用法_Java中单例模式的实现

保证单例的核心在于控制实例的创建。

Java中单例的用法_Java中单例模式的实现

解决方案

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

Java中单例的用法_Java中单例模式的实现

实现单例模式有几种常见的方式,各有利弊:

  1. 饿汉式:

    public class Singleton {
        private static final Singleton instance = new Singleton();
    
        private Singleton() {
            // 防止外部通过new创建实例
        }
    
        public static Singleton getInstance() {
            return instance;
        }
    }

    饿汉式在类加载的时候就完成了初始化,所以是线程安全的。 优点是实现简单,线程安全。 缺点是如果单例对象从始至终都没用到,会造成资源浪费。

  2. 懒汉式:

    public class Singleton {
        private static Singleton instance;
    
        private Singleton() {
            // 防止外部通过new创建实例
        }
    
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }

    懒汉式在第一次调用getInstance()方法时才创建实例。 优点是延迟加载,只有在真正使用的时候才会创建。 缺点是需要使用synchronized关键字来保证线程安全,在高并发场景下性能会受到影响。

  3. 双重校验锁(DCL):

    public class Singleton {
        private volatile static Singleton instance;
    
        private Singleton() {
            // 防止外部通过new创建实例
        }
    
        public static Singleton getInstance() {
            if (instance == null) {
                synchronized (Singleton.class) {
                    if (instance == null) {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    DCL在懒汉式的基础上进行了优化,只有在实例未被创建时才进行同步。 使用volatile关键字是为了防止指令重排序导致的问题。 优点是延迟加载,线程安全,性能较高。 缺点是实现较为复杂,需要注意volatile关键字的使用。

  4. 静态内部类:

    public class Singleton {
        private Singleton() {
            // 防止外部通过new创建实例
        }
    
        private static class SingletonHolder {
            private static final Singleton instance = new Singleton();
        }
    
        public static Singleton getInstance() {
            return SingletonHolder.instance;
        }
    }

    静态内部类利用了类加载机制来保证线程安全,同时实现了延迟加载。 优点是延迟加载,线程安全,实现简单。 缺点是稍微难以理解。

  5. 枚举:

    public enum Singleton {
        INSTANCE;
    
        public void doSomething() {
            // ...
        }
    }

    枚举是实现单例模式最简单的方式,并且可以防止反射攻击和序列化攻击。 优点是实现简单,线程安全,防止反射攻击和序列化攻击。 缺点是不能延迟加载,枚举类型在类加载时就会被初始化。

单例模式在多线程环境下如何保证线程安全?

线程安全是单例模式中一个非常重要的考虑因素。 如果多个线程同时调用getInstance()方法,可能会导致创建多个实例。 上述几种实现方式中,饿汉式、静态内部类和枚举天生就是线程安全的,因为它们在类加载时就已经完成了初始化。 懒汉式和DCL需要使用同步机制来保证线程安全。 懒汉式使用synchronized关键字,DCL使用双重校验锁和volatile关键字。

为什么DCL需要使用volatile关键字?

java-api-doc-generator
java-api-doc-generator

分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。

下载

volatile关键字的作用是防止指令重排序。 在DCL中,instance = new Singleton()这行代码实际上包含了三个步骤:

  1. 分配内存空间。

  2. 初始化对象。

  3. 将instance指向分配的内存空间。

    由于指令重排序的存在,步骤2和步骤3的顺序可能被颠倒。 如果线程A执行了步骤1和步骤3,但步骤2尚未执行,此时线程B调用getInstance()方法,判断instance不为null,直接返回instance,但此时instance指向的对象尚未初始化,线程B使用该对象可能会出现问题。 使用volatile关键字可以防止指令重排序,保证步骤2在步骤3之前执行。

单例模式如何防止反射攻击?

反射攻击是指通过反射机制来绕过单例模式的限制,创建多个实例。 对于饿汉式、懒汉式和DCL,可以通过在构造函数中判断实例是否已经存在,如果存在则抛出异常来防止反射攻击。

public class Singleton {
    private static Singleton instance;

    private Singleton() {
        if (instance != null) {
            throw new IllegalStateException("Singleton already initialized.");
        }
    }

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

对于静态内部类,由于其构造函数也是私有的,并且无法通过反射访问静态内部类,因此可以防止反射攻击。 枚举天生就可以防止反射攻击,因为Java虚拟机保证枚举类型的实例只能被创建一次。

单例模式如何防止序列化攻击?

序列化攻击是指通过序列化和反序列化来绕过单例模式的限制,创建多个实例。 当一个单例对象被序列化和反序列化后,会得到一个新的对象,破坏了单例性。 为了防止序列化攻击,可以实现readResolve()方法,在反序列化时返回已有的单例对象。

public class Singleton implements java.io.Serializable {
    private static final Singleton instance = new Singleton();

    private Singleton() {
        // 防止外部通过new创建实例
    }

    public static Singleton getInstance() {
        return instance;
    }

    private Object readResolve() {
        return instance;
    }
}

枚举天生就可以防止序列化攻击,因为Java虚拟机保证枚举类型的实例只能被创建一次,即使进行序列化和反序列化,得到的仍然是同一个实例。

单例模式的优缺点是什么?

优点:

  • 控制实例数量,节省资源。
  • 提供全局访问点,方便访问。
  • 可以延迟加载,提高性能。

缺点:

  • 可能会隐藏类的依赖关系。
  • 在多线程环境下需要考虑线程安全问题。
  • 不易于测试,因为单例对象的状态是全局的。

什么时候应该使用单例模式?

单例模式适用于以下场景:

  • 需要控制实例数量的类。
  • 需要提供全局访问点的类。
  • 需要延迟加载的类。

例如:

  • 数据库连接池。
  • 配置信息。
  • 线程池。
  • 日志管理器。

选择哪种单例模式的实现方式取决于具体的应用场景。 如果对性能要求不高,可以使用饿汉式或枚举。 如果需要延迟加载,可以使用懒汉式、DCL或静态内部类。 如果需要防止反射攻击和序列化攻击,可以使用枚举。 实际开发中,可以根据具体的需求选择最合适的实现方式。

热门AI工具

更多
UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

蛙蛙写作

一款AI论文写作工具,主要用于超级AI智能写作助手,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

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

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

549

2023.09.22

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

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

1698

2024.03.01

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

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

794

2025.10.23

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

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

4438

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

1229

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

423

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

579

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

429

2026.02.06

Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

20

2026.10.28

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn