Java中的设计模式:单例模式详解
字数 790 2025-11-05 23:47:54

Java中的设计模式:单例模式详解

描述
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。这种设计模式在需要控制资源访问(如数据库连接池、配置管理器、日志记录器等)的场景中非常有用。

核心要点

  1. 私有化构造函数:防止外部通过new创建实例
  2. 静态私有成员变量:存储唯一实例
  3. 静态公有方法:提供全局访问入口

演进过程

1. 饿汉式(Eager Initialization)

public class Singleton {
    // 类加载时就创建实例
    private static final Singleton INSTANCE = new Singleton();
    
    // 私有构造函数
    private Singleton() {}
    
    // 全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
  • 优点:实现简单,线程安全
  • 缺点:如果实例未被使用,会造成内存浪费

2. 懒汉式(Lazy Initialization)

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 {
    private static Singleton instance;
    
    private Singleton() {}
    
    // 方法同步,保证线程安全
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
  • 优点:线程安全
  • 缺点:每次获取实例都要同步,性能较差

4. 双重检查锁(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关键字:防止JVM指令重排序导致的空指针问题

5. 静态内部类(Holder)方式

public class Singleton {
    private Singleton() {}
    
    // 静态内部类在第一次使用时加载
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
  • 优点:线程安全,延迟加载,性能好
  • 原理:利用类加载机制保证线程安全

6. 枚举方式(推荐)

public enum Singleton {
    INSTANCE;
    
    public void doSomething() {
        // 业务方法
    }
}
  • 优点:线程安全,防止反射攻击,防止反序列化重新创建对象
  • 这是《Effective Java》作者Joshua Bloch推荐的方式

关键问题解析

1. 为什么需要两次null检查?

  • 第一次检查:避免不必要的同步,提高性能
  • 第二次检查:确保在同步块内只有一个线程能创建实例

2. volatile关键字的作用

instance = new Singleton(); // 这行代码分为3步:
// 1. 分配内存空间
// 2. 初始化对象
// 3. 将instance指向内存地址

如果没有volatile,可能发生指令重排序,导致其他线程拿到未初始化的对象。

3. 防止反射攻击

public class Singleton {
    private static boolean initialized = false;
    
    private Singleton() {
        synchronized (Singleton.class) {
            if (initialized) {
                throw new RuntimeException("单例模式被破坏!");
            }
            initialized = true;
        }
    }
}

使用场景

  • 需要频繁创建和销毁的对象
  • 创建对象耗时过多或资源消耗过大
  • 工具类对象
  • 数据库连接池等资源管理器

每种实现方式都有其适用场景,应根据具体需求选择最合适的实现方案。

Java中的设计模式:单例模式详解 描述 单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。这种设计模式在需要控制资源访问(如数据库连接池、配置管理器、日志记录器等)的场景中非常有用。 核心要点 私有化构造函数:防止外部通过new创建实例 静态私有成员变量:存储唯一实例 静态公有方法:提供全局访问入口 演进过程 1. 饿汉式(Eager Initialization) 优点:实现简单,线程安全 缺点:如果实例未被使用,会造成内存浪费 2. 懒汉式(Lazy Initialization) 优点:延迟加载,节省内存 缺点:线程不安全,多线程环境下可能创建多个实例 3. 线程安全的懒汉式 优点:线程安全 缺点:每次获取实例都要同步,性能较差 4. 双重检查锁(Double-Checked Locking) 第一次检查:避免不必要的同步 第二次检查:确保只有一个线程创建实例 volatile关键字:防止JVM指令重排序导致的空指针问题 5. 静态内部类(Holder)方式 优点:线程安全,延迟加载,性能好 原理:利用类加载机制保证线程安全 6. 枚举方式(推荐) 优点:线程安全,防止反射攻击,防止反序列化重新创建对象 这是《Effective Java》作者Joshua Bloch推荐的方式 关键问题解析 1. 为什么需要两次null检查? 第一次检查:避免不必要的同步,提高性能 第二次检查:确保在同步块内只有一个线程能创建实例 2. volatile关键字的作用 如果没有volatile,可能发生指令重排序,导致其他线程拿到未初始化的对象。 3. 防止反射攻击 使用场景 需要频繁创建和销毁的对象 创建对象耗时过多或资源消耗过大 工具类对象 数据库连接池等资源管理器 每种实现方式都有其适用场景,应根据具体需求选择最合适的实现方案。