实现线程安全的单例模式
字数 725 2025-11-06 12:41:20
实现线程安全的单例模式
题目描述
单例模式是一种常见的设计模式,确保一个类只有一个实例,并提供一个全局访问点。在多线程环境下,需要保证单例的线程安全性,避免创建多个实例。本题要求实现一个线程安全的单例模式,并解释其原理。
关键知识点
- 懒汉式(Lazy Initialization)与饿汉式(Eager Initialization)
- 双重检查锁定(Double-Checked Locking)
- 静态内部类(Static Inner Class)
- volatile关键字的作用
解题步骤
-
基础懒汉式(非线程安全)
- 延迟创建实例,但多线程下可能重复创建。
public class Singleton { private static Singleton instance; private Singleton() {} // 私有构造函数 public static Singleton getInstance() { if (instance == null) { // 线程A和B可能同时进入此条件 instance = new Singleton(); } return instance; } }- 问题:多个线程同时通过
instance == null检查时,会创建多个实例。
-
懒汉式+同步方法(线程安全但效率低)
- 通过
synchronized保证线程安全,但每次调用都加锁,性能差。
public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } - 通过
-
双重检查锁定(DCL)
- 在加锁前后各检查一次实例是否存在,避免不必要的锁竞争。
public class Singleton { private static volatile Singleton instance; // 必须使用volatile private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { // 加锁 if (instance == null) { // 第二次检查 instance = new Singleton(); } } } return instance; } }- volatile的作用:禁止指令重排序,防止其他线程获取到未初始化完成的对象(详见JVM的“指令重排序”问题)。
-
静态内部类(推荐方案)
- 利用JVM类加载机制保证线程安全,且实现懒加载。
public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; // 首次调用时加载内部类 } }- 原理:JVM在加载类时是线程安全的,静态内部类只在
getInstance()首次调用时被加载,且静态变量初始化只执行一次。
-
枚举单例(最简洁的线程安全方案)
- 枚举实例由JVM保证唯一性,且能防止反射攻击。
public enum Singleton { INSTANCE; public void doSomething() { ... } }
总结
- 懒汉式DCL需注意
volatile的使用,避免指令重排序。 - 静态内部类方案无需显式同步,代码简洁且高效。
- 枚举单例是《Effective Java》推荐的方式,但某些场景下不够灵活(如需继承其他类)。