# 单例模式

## 目录
- [单例模式概念](#单例模式概念)
- [饿汉式](#饿汉式)
- [懒汉式](#懒汉式)
- [双重检查锁定](#双重检查锁定)
- [静态内部类](#静态内部类)
- [枚举单例](#枚举单例)
- [单例模式最佳实践](#单例模式最佳实践)
- [面试常见问题](#面试常见问题)

---

## 单例模式概念

### 定义

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

### 使用场景

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

---

## 饿汉式

### 实现方式

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

### 特点

```java
// 优点：
// 1. 线程安全
// 2. 实现简单

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

---

## 懒汉式

### 实现方式

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

### 线程安全问题

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

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

// 缺点：每次调用都要加锁，性能差
```

---

## 双重检查锁定

### 实现方式

```java
// 双重检查锁定（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;
    }
}
```

### 关键点

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

---

## 静态内部类

### 实现方式

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

### 特点

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

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

---

## 枚举单例

### 实现方式

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

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

### 特点

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

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

---

## 单例模式最佳实践

### 1. 选择合适的方式

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

### 2. 注意线程安全

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

### 3. 避免内存泄漏

```java
// 单例持有 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年*
