766 words
4 minutes
singleton pattern

单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。在多线程环境下,单例模式的实现需要特别注意线程安全问题。以下是几种常见的线程安全的单例模式实现方式:


1. 饿汉式(Eager Initialization)#

在类加载时就创建实例,线程安全,但可能会造成资源浪费(如果实例未被使用)。

public class Singleton {
    // 在类加载时创建实例
    private static final Singleton INSTANCE = new Singleton();

    // 私有构造函数,防止外部实例化
    private Singleton() {}

    // 提供全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

优点

  • 实现简单,线程安全。
  • 没有加锁性能开销。

缺点

  • 如果实例未被使用,会造成资源浪费。

Chain of Responsibility Pattern

2. 懒汉式(Lazy Initialization)#

在第一次使用时才创建实例,需要加锁保证线程安全。

2.1 简单加锁(线程安全但性能较差)#

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    // 加锁保证线程安全
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点

  • 懒加载,节省资源。

缺点

  • 每次调用 getInstance 都需要加锁,性能较差。

2.2 双重检查锁(Double-Checked Locking)#

在加锁的基础上进行双重检查,减少加锁次数,提高性能。

public class Singleton {
    // 使用 volatile 保证可见性和禁止指令重排序
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) { // 第一次检查
            synchronized (Singleton.class) { // 加锁
                if (instance == null) { // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

优点

  • 懒加载,节省资源。
  • 只有在第一次创建实例时加锁,性能较好。

缺点

  • 实现稍复杂,需要理解 volatile 和双重检查的意义。

3. 静态内部类(Static Inner Class)#

利用类加载机制保证线程安全,同时实现懒加载。

public class Singleton {
    private Singleton() {}

    // 静态内部类
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

优点

  • 懒加载,节省资源。
  • 线程安全,无需加锁。
  • 实现简单。

缺点

  • 无法传递参数初始化实例。

4. 枚举(Enum)#

枚举实现单例是《Effective Java》推荐的方式,简洁且线程安全。

public enum Singleton {
    INSTANCE;

    // 可以添加方法
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

优点

  • 线程安全。
  • 防止反射和序列化破坏单例。
  • 实现简单。

缺点

  • 不够灵活(例如无法懒加载)。

总结#

实现方式线程安全懒加载性能防止反射/序列化破坏
饿汉式
懒汉式(简单加锁)
双重检查锁
静态内部类
枚举
  • 如果需要懒加载且性能要求高,推荐使用 双重检查锁静态内部类
  • 如果需要绝对的安全性和简洁性,推荐使用 枚举
singleton pattern
https://masonry440921.github.io/blog/posts/singletonpattern/
Author
mason
Published at
2025-02-20