839 words
4 minutes
单例模式

1. 基本介绍#

单例模式(Singleton Pattern)是一种设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点来获取该实例。它主要解决的问题是如何保证某个类的实例在整个应用程序中唯一,并且能够在需要时轻松访问。

单例模式的关键点:#

  1. 唯一性:类只能有一个实例,确保系统中只会有这个唯一的对象。
  2. 全局访问:提供一个全局访问点来获取该实例。通常通过一个静态方法来获取实例。

单例模式的应用场景:#

  • 日志记录器:全局唯一的日志工具类。
  • 数据库连接池:多个线程共享一个数据库连接池。
  • 线程池:线程池是全局唯一的,避免重复创建。
  • 缓存管理:全局唯一的缓存对象。

2. Java实现#

1. 饿汉式(Eager Initialization)#

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

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

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

    // 提供全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
  • 优点:实现简单,线程安全。
  • 缺点:如果实例未被使用,会造成资源浪费。

2. 懒汉式(Lazy Initialization)#

在第一次调用 getInstance() 时创建实例,节省资源,但需要处理多线程问题。

(1)非线程安全的懒汉式:多线程环境下可能会创建多个实例

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

(2)线程安全的懒汉式(加锁):每次调用 getInstance() 都会加锁,性能较差。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

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

在懒汉式的基础上,通过双重检查减少加锁的开销。

public class Singleton {
    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 关键字防止指令重排序。

4. 静态内部类(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;
    }
}
  • 优点:线程安全,懒加载,实现简单。
  • 缺点:无法传递参数初始化实例。

5. 枚举(Enum)#

利用枚举的特性实现单例,线程安全且防止反射攻击。

public enum Singleton {
    INSTANCE;

    public void doSomething() {
        System.out.println("Doing something...");
    }
}
  • 优点:线程安全,防止反射和序列化破坏单例。
  • 缺点:不够灵活(如无法延迟加载)。

6. ThreadLocal 单例#

为每个线程提供一个单例实例,线程间隔离。

public class ThreadLocalSingleton {
    private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
        ThreadLocal.withInitial(ThreadLocalSingleton::new);

    private ThreadLocalSingleton() {}

    public static ThreadLocalSingleton getInstance() {
        return threadLocalInstance.get();
    }
}
  • 优点:线程间隔离,适合线程内单例场景。
  • 缺点:每个线程都有自己的实例,不是全局单例。
单例模式
https://mj3622.github.io/posts/编程实践/单例模式/
Author
Minjer
Published at
2025-02-07