目录

设计模式-单例模式

设计模式-单例模式

Java 实现单例模式的方式主要有以下几种,每种方式都有其 优缺点 和适用场景。


1. 饿汉式(Eager Initialization)

实现方式

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    
    private Singleton() {} // 私有构造方法,防止外部实例化
    
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

优缺点

优点

  • 实现简单,类加载时即创建实例,线程安全。
  • 访问速度快,调用 getInstance() 方法不会有同步开销。

缺点

  • 可能造成资源浪费 :即使实例可能长期未使用,仍然会在类加载时创建。

适用场景

  • 对象创建成本低 ,且 类会被频繁使用 的场景(如工具类)。

2. 懒汉式(Lazy Initialization,非线程安全)

实现方式

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优缺点

优点

  • 只有 在第一次调用时才创建实例 ,节省资源。

缺点

  • 非线程安全 :多个线程同时调用 getInstance() 可能导致多个实例被创建。

适用场景

  • 单线程环境 ,或者 不在多线程场景下使用

3. 线程安全的懒汉式(同步方法)

实现方式

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优缺点

优点

  • 线程安全 ,可确保只有一个实例被创建。

缺点

  • synchronized 关键字会 影响性能 ,每次调用 getInstance() 都会加锁。

适用场景

  • 需要 保证线程安全 ,但实例创建 不会频繁调用 的场景。

4. 双重检查锁(Double-Checked Locking,推荐)

实现方式

public class Singleton {
    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 防止指令重排序 ,Java 1.5 之前的版本不支持。

适用场景

  • 多线程环境 ,且 性能要求较高 的场景。

5. 静态内部类(推荐)

实现方式

public class Singleton {
    private Singleton() {}

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

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

优缺点

优点

  • 线程安全 ,利用 JVM 类加载机制 保证只会初始化一次。
  • 只有 在调用 getInstance() 时才会创建实例 ,节省资源(懒加载)。
  • 无锁 ,性能高。

缺点

  • 无法传递参数 ,如果需要参数化实例,则无法使用该方法。

适用场景

  • 高并发环境 ,且 希望使用懒加载 的场景。

6. 枚举单例(最推荐)

实现方式

public enum Singleton {
    INSTANCE;

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

优缺点

优点

  • 线程安全 ,由 JVM 保证。
  • 防止反序列化破坏单例 ,因为枚举不会创建新的实例。
  • 代码最简洁 ,推荐使用。

缺点

  • 无法懒加载 ,类加载时即创建实例。
  • 不能继承其他类 (但可以实现接口)。

适用场景

  • 绝对保证单例性 的场景,如 数据库连接管理、日志管理器 等。

7. 通过 ThreadLocal 实现(每个线程单例)

实现方式

public class ThreadLocalSingleton {
    private static final ThreadLocal<ThreadLocalSingleton> instance =
        ThreadLocal.withInitial(ThreadLocalSingleton::new);

    private ThreadLocalSingleton() {}

    public static ThreadLocalSingleton getInstance() {
        return instance.get();
    }
}

优缺点

优点

  • 线程隔离 ,每个线程都有自己独立的实例。
  • 避免了全局同步,适用于 多线程数据隔离场景

缺点

  • 无法做到全局唯一单例 ,只在 单个线程内保持单例

适用场景

  • 每个线程需要独立状态 的场景,如 用户会话、数据库连接

总结

方式线程安全是否懒加载优点缺点适用场景
饿汉式实现简单,访问快可能造成资源浪费适用于常用单例
懒汉式按需加载,节省资源线程不安全仅限单线程
同步懒汉线程安全synchronized 影响性能适用于低频率调用
双重检查锁线程安全,性能优代码较复杂推荐,高并发环境
静态内部类线程安全,懒加载无法传参推荐,JVM 保证
枚举单例最安全,防反序列化不能继承类最推荐,绝对单例
ThreadLocal线程隔离不是全局单例适用于每线程独立实例

如果 要保证绝对的单例性 ,推荐 枚举单例Enum )。

如果 需要懒加载且高性能 ,推荐 静态内部类双重检查锁