单例模式(Singleton Pattern)

时间:2024-11-21 12:26:00

单例模式(Singleton Pattern)

单例模式是一种 创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。


原理

  1. 核心思想:控制实例化过程,确保一个类只能创建一个实例。
  2. 实现方式
    • 将构造方法设置为私有。
    • 提供一个静态方法返回唯一实例。
  3. 参与角色
    • 单例类(Singleton):负责自己唯一实例的创建和全局访问。
    • 客户端(Client):通过单例类的访问方法获取实例。

优点

  1. 节省资源:单例对象可以被多次重复使用,尤其是资源密集型对象(如数据库连接)。
  2. 全局访问点:提供一个全局共享对象,便于在系统中访问。
  3. 控制实例数量:确保系统中只有一个对象实例,避免重复实例化问题。

缺点

  1. 违背单一职责原则:单例类同时负责实例控制和自身功能。
  2. 并发问题:需要处理多线程场景中的并发访问。
  3. 难以扩展:单例模式难以被继承和测试。

单例模式实现方式

1. 饿汉式(线程安全)
  • 实例在类加载时创建,线程安全。
  • 缺点:如果实例未被使用,会造成内存浪费。
public class Singleton {
    // 静态实例在类加载时创建
    private static final Singleton INSTANCE = new Singleton();

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

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

2. 懒汉式(线程不安全)
  • 实例在首次使用时创建,节省资源。
  • 缺点:多线程环境下可能出现多个实例。
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton(); // 可能出现线程安全问题
        }
        return instance;
    }
}

3. 双重检查锁(线程安全)
  • 结合懒汉式和线程安全的优点,推荐使用。
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;
    }
}

4. 静态内部类(线程安全)
  • 利用类加载机制实现延迟加载,且线程安全。
public class Singleton {
    private Singleton() {}

    // 静态内部类持有单例实例
    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() {
        System.out.println("Doing something...");
    }
}

示例代码

以日志管理器为例,实现单例模式:

public class Logger {
    // 双重检查锁实现单例
    private static volatile Logger instance;

    private Logger() {
        // 私有构造方法
    }

    public static Logger getInstance() {
        if (instance == null) {
            synchronized (Logger.class) {
                if (instance == null) {
                    instance = new Logger();
                }
            }
        }
        return instance;
    }

    public void log(String message) {
        System.out.println("Log: " + message);
    }
}

// 客户端代码
public class SingletonExample {
    public static void main(String[] args) {
        Logger logger = Logger.getInstance();
        logger.log("Singleton pattern in action!"); // Output: Log: Singleton pattern in action!
    }
}

适用场景

  1. 需要唯一实例
    • 数据库连接池。
    • 配置文件管理器。
    • 日志管理器。
  2. 需要全局共享资源:例如系统级别的缓存或计数器。

小结

  • 单例模式提供了一个全局的访问点,保证类的唯一实例。
  • 在实际开发中,推荐使用 枚举实现静态内部类实现,既简单又高效,能够很好地应对多线程问题和序列化攻击。