设计模式-单例模式

单例模式

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)。

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

相关推荐
2501_92489052几秒前
商超场景徘徊识别误报率↓79%!陌讯多模态时序融合算法落地优化
java·大数据·人工智能·深度学习·算法·目标检测·计算机视觉
從南走到北40 分钟前
JAVA国际版东郊到家同城按摩服务美容美发私教到店服务系统源码支持Android+IOS+H5
android·java·开发语言·ios·微信·微信小程序·小程序
qianmoq1 小时前
第04章:数字流专题:IntStream让数学计算更简单
java
带只拖鞋去流浪2 小时前
Java集合(Collection、Map、转换)
java
超级小忍2 小时前
使用 GraalVM Native Image 将 Spring Boot 应用编译为跨平台原生镜像:完整指南
java·spring boot·后端
野犬寒鸦2 小时前
力扣hot100:搜索二维矩阵与在排序数组中查找元素的第一个和最后一个位置(74,34)
java·数据结构·算法·leetcode·list
AlenLi3 小时前
JavaScript - 观察者模式的实现与应用场景
前端·设计模式
cxyxiaokui0013 小时前
线程池的“变形记”:核心线程数居然能随时变大变小?
java·面试
灵魂猎手3 小时前
11. Mybatis SQL解析源码分析
java·后端·源码
努力的小郑4 小时前
别再说你会 new Object() 了!JVM 类加载的真相,绝对和你想的不一样
java·jvm·面试