设计模式-单例模式

单例模式

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


1. 饿汉式(Eager Initialization)

实现方式

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

优缺点

优点

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

缺点

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

适用场景

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

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

实现方式

java 复制代码
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

优缺点

优点

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

缺点

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

适用场景

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

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

实现方式

java 复制代码
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,推荐)

实现方式

java 复制代码
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. 静态内部类(推荐)

实现方式

java 复制代码
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. 枚举单例(最推荐)

实现方式

java 复制代码
public enum Singleton {
    INSTANCE;

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

优缺点

优点

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

缺点

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

适用场景

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

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

实现方式

java 复制代码
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)。

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

相关推荐
鹏易灵4 分钟前
C++——2.常量与 const、constexpr 初识详解
java·开发语言·c++
qq_452396237 分钟前
第十三篇:《K8s 安全基础:RBAC、ServiceAccount、Pod Security》
java·安全·kubernetes
w_t_y_y28 分钟前
Agent设计模式(四)多模态融合模式(Multi-Modal Fusion)
设计模式
张某布响丸辣31 分钟前
Spring AI 极简入门:Java 开发者快速上手 AI 开发
java·人工智能·spring·springai
java1234_小锋33 分钟前
请描述 Spring Boot 的启动流程,包括 SpringApplication 的初始化和 run 方法的核心步骤。
java·数据库·spring boot
疯狂成瘾者35 分钟前
Java 集合 LinkedList 详解:链表结构、常用方法和队列使用
java·开发语言·链表
lanyxp41 分钟前
Sentinel 管不到 SQL 这一层——我写了个 MyBatis SQL 熔断器
java
武子康1 小时前
Java-28 深入浅出 Spring 实现简易Ioc-04 在上节的业务下手动实现AOP
java·后端·mybatis
慧一居士1 小时前
SpringCloud 微服务Feigin 用的完整调用端和被调用的示例
java·spring cloud