单例模式(Singleton Pattern)

单例模式(Singleton Pattern)

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


原理

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

优点

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

缺点

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

单例模式实现方式

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

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

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

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

    private Singleton() {}

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

3. 双重检查锁(线程安全)
  • 结合懒汉式和线程安全的优点,推荐使用。
java 复制代码
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. 静态内部类(线程安全)
  • 利用类加载机制实现延迟加载,且线程安全。
java 复制代码
public class Singleton {
    private Singleton() {}

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

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

5. 枚举实现(推荐)
  • 使用枚举类实现单例是最简洁和安全的方式。
  • 枚举类天然防止序列化和反射攻击。
java 复制代码
public enum Singleton {
    INSTANCE;

    public void doSomething() {
        System.out.println("Doing something...");
    }
}

示例代码

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

java 复制代码
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. 需要全局共享资源:例如系统级别的缓存或计数器。

小结

  • 单例模式提供了一个全局的访问点,保证类的唯一实例。
  • 在实际开发中,推荐使用 枚举实现静态内部类实现,既简单又高效,能够很好地应对多线程问题和序列化攻击。
相关推荐
程序员小寒3 天前
JavaScript设计模式(一):单例模式实现与应用
javascript·单例模式·设计模式
.select.3 天前
C++ 单例模式
java·c++·单例模式
bbq粉刷匠3 天前
Java--多线程--单例模式
java·开发语言·单例模式
砍光二叉树4 天前
【设计模式】创建型-单例模式
单例模式·设计模式
魑魅魍魉都是鬼4 天前
Android:java kotlin 单例模式
android·java·单例模式
biter down4 天前
C++ 单例模式:饿汉与懒汉模式
开发语言·c++·单例模式
mingshili5 天前
[架构设计] 依赖注入优于单例模式
单例模式·架构设计
一只大袋鼠5 天前
并发编程(二十三):单例模式(二):静态/非静态方法:单例内存优化关键
java·单例模式·并发编程
一叶飘零_sweeeet5 天前
volatile 关键字深度拆解:从内存屏障底层到单例模式的工业级架构设计
单例模式·volatile
一只大袋鼠5 天前
并发编程(二十四):单例模式(三):构造方法私有:单例模式的 “第一道防线”
java·单例模式·并发编程