Files
mkdocs/docs/android面试/设计模式/单例模式.md
2026-01-15 11:53:37 +08:00

5.1 KiB
Raw Blame History

单例模式

目录


单例模式概念

定义

// 单例模式:确保一个类只有一个实例
// 提供全局访问点
// 适用于需要唯一实例的场景

使用场景

// 1. 配置管理类
// 2. 日志管理类
// 3. 数据库连接池
// 4. 线程池
// 5. 缓存管理

饿汉式

实现方式

// 饿汉式:类加载时就创建实例
public class Singleton {
    // 私有静态实例
    private static Singleton instance = new Singleton();
    
    // 私有构造函数
    private Singleton() {
    }
    
    // 公共静态方法
    public static Singleton getInstance() {
        return instance;
    }
}

特点

// 优点:
// 1. 线程安全
// 2. 实现简单

// 缺点:
// 1. 类加载时就创建,可能浪费内存
// 2. 如果不需要使用,也会创建实例

懒汉式

实现方式

// 懒汉式:第一次使用时创建实例
public class Singleton {
    private static Singleton instance;
    
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

线程安全问题

// ❌ 问题:多线程不安全
// 多个线程可能同时创建多个实例

// ✅ 解决:加锁
public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

// 缺点:每次调用都要加锁,性能差

双重检查锁定

实现方式

// 双重检查锁定DCL
public class Singleton {
    private volatile static Singleton instance;
    
    private Singleton() {
    }
    
    public static Singleton getInstance() {
        if (instance == null) { // 第一次检查
            synchronized (Singleton.class) {
                if (instance == null) { // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

关键点

// 1. 两次检查:减少锁竞争
// 2. volatile保证可见性防止指令重排序
// 3. synchronized保证线程安全

静态内部类

实现方式

// 静态内部类:推荐方式
public class Singleton {
    private Singleton() {
    }
    
    // 静态内部类
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

特点

// 优点:
// 1. 线程安全
// 2. 懒加载:第一次调用时才创建
// 3. 性能好:不需要加锁
// 4. 实现简单

// 原理:
// 类加载时,静态内部类不会加载
// 只有调用 getInstance() 时,才会加载静态内部类
// JVM 保证类加载的线程安全

枚举单例

实现方式

// 枚举单例:最推荐的方式
public enum Singleton {
    INSTANCE;
    
    public void doSomething() {
        // 方法实现
    }
}

// 使用
Singleton.INSTANCE.doSomething();

特点

// 优点:
// 1. 线程安全
// 2. 防止反序列化创建新实例
// 3. 防止反射创建新实例
// 4. 实现简单

// 缺点:
// 1. 不能延迟加载
// 2. 枚举类不能继承其他类

单例模式最佳实践

1. 选择合适的方式

// 简单场景:饿汉式
// 需要懒加载:静态内部类
// 需要防止反射和反序列化:枚举单例

2. 注意线程安全

// 多线程环境必须保证线程安全
// 使用 volatile 和 synchronized
// 或使用静态内部类、枚举

3. 避免内存泄漏

// 单例持有 Context 时,使用 Application Context
private static Context sContext = context.getApplicationContext();

面试常见问题

Q1: 单例模式的实现方式?

答案:

  1. 饿汉式:类加载时创建,线程安全
  2. 懒汉式:使用时创建,需要加锁
  3. 双重检查锁定:两次检查,使用 volatile
  4. 静态内部类:推荐,懒加载,线程安全
  5. 枚举单例:最推荐,防止反射和反序列化

Q2: 双重检查锁定为什么需要 volatile

答案:

  • 防止指令重排序
  • 保证可见性
  • 确保多线程环境下正确初始化

Q3: 静态内部类为什么是线程安全的?

答案:

  • JVM 保证类加载的线程安全
  • 静态内部类在第一次调用时才加载
  • 类加载时创建实例,天然线程安全

Q4: 枚举单例的优势?

答案:

  1. 线程安全
  2. 防止反序列化创建新实例
  3. 防止反射创建新实例
  4. 实现简单

最后更新2024年