Java中单例模式的几种实现方式总结
date
Aug 20, 2025
AI 摘要
slug
java-singleton-pattern-implementations
status
Published
tags
android
summary
单例模式(Singleton Pattern)是Java中最基本和最常用的设计模式之一。该模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在需要频繁创建和销G毁对象或者需要一个全局唯一的对象(例如,线程池、缓存、日志对象等)的场景下,单例模式尤为重要。
type
Post
单例模式(Singleton Pattern)是Java中最基本和最常用的设计模式之一。该模式确保一个类只有一个实例,并提供一个全局访问点来访问该实例。在需要频繁创建和销G毁对象或者需要一个全局唯一的对象(例如,线程池、缓存、日志对象等)的场景下,单例模式尤为重要。
以下总结了Java中几种常见的单例模式实现方式,并分析了各自的优缺点。
1. 饿汉式(Eager Initialization)
饿汉式在类加载时就立即创建实例,因此是线程安全的。
优点:
- 实现简单,代码可读性高。
- 在类加载时就完成了实例化,避免了多线程同步问题,是线程安全的。
缺点:
- 在类加载时就创建实例,即使后续从未使用过该实例,也会占用内存空间,可能造成资源浪费。
2. 懒汉式(Lazy Initialization)
懒汉式在第一次调用
getInstance()
方法时才创建实例。2.1 基础懒汉式(非线程安全)
优点:
- 实现了懒加载,只有在需要时才创建实例,节约了资源。
缺点:
- 在多线程环境下是非线程安全的。如果多个线程同时进入
if (instance == null)
判断,并且此时instance
都为null
,那么将会有多个线程创建出多个实例,违背了单例模式的初衷。
2.2 线程安全的懒汉式(同步方法)
通过在
getInstance()
方法上添加synchronized
关键字,可以保证线程安全。优点:
- 解决了多线程环境下的线程安全问题。
缺点:
- 每次调用
getInstance()
方法时都需要进行同步,即使实例已经被创建。这会导致不必要的性能开销,尤其是在高并发场景下。
3. 双重检查锁定(Double-Checked Locking)
双重检查锁定是对线程安全的懒汉式的一种优化,旨在减少不必要的同步开销。
关键点:
- 使用
volatile
关键字修饰instance
变量,确保其可见性和禁止指令重排。
- 进行两次
if (instance == null)
检查,第一次检查是为了避免在实例已存在的情况下进入同步代码块,从而提高性能。第二次检查是为了在同步代码块内部再次确认实例是否被创建,防止多个线程同时通过第一次检查后重复创建实例。
优点:
- 兼顾了线程安全和懒加载的性能。只有在第一次创建实例时才会进入同步代码块,后续的调用将直接返回已创建的实例,性能较高。
缺点:
- 实现相对复杂,容易出错。
volatile
关键字是必不可少的,否则可能由于指令重排导致获取到未完全初始化的对象。
4. 【推荐】静态内部类(Static Inner Class)
这是目前被广泛推荐的一种实现方式,它利用了JVM类加载机制来保证线程安全和懒加载。
原理:
- 当
StaticInnerClassSingleton
类被加载时,其静态内部类SingletonHolder
并不会被加载。
- 只有当第一次调用
getInstance()
方法时,JVM才会加载SingletonHolder
类,并初始化INSTANCE
。
- JVM在加载类时是线程安全的,因此保证了只有一个线程可以初始化
INSTANCE
。
优点:
- 实现了懒加载。
- 由JVM保证线程安全,无需任何同步代码,性能高。
- 实现简单,代码清晰。
5. 枚举(Enum)
这是《Effective Java》作者Joshua Bloch推荐的最佳实现方式。
优点:
- 实现最简单。
- 天然线程安全。
- 能有效防止通过反射和反序列化创建新的对象,从而破坏单例。
缺点:
- 不具备懒加载的特性。
总结
实现方式 | 线程安全 | 懒加载 | 推荐指数 | 备注 |
饿汉式 | 是 | 否 | ⭐⭐⭐ | 实现简单,但可能造成资源浪费。 |
懒汉式(非线程安全) | 否 | 是 | ⭐ | 仅限单线程环境使用。 |
懒汉式(同步方法) | 是 | 是 | ⭐⭐ | 性能开销较大,不推荐。 |
双重检查锁定 | 是 | 是 | ⭐⭐⭐⭐ | 实现较复杂,需正确使用 volatile 。 |
静态内部类 | 是 | 是 | ⭐⭐⭐⭐⭐ | 兼具懒加载和线程安全,实现简单,推荐使用。 |
枚举 | 是 | 否 | ⭐⭐⭐⭐⭐ | 最简洁、最安全的实现方式,能防止反射和反序列化攻击。 |
在实际开发中,静态内部类和枚举是两种最被推崇的单例模式实现方式。如果需要懒加载,静态内部类是绝佳的选择;如果不需要懒加载,或者对防止反射和反序列化有强烈的需求,枚举则是最简单且最安全的方式。