二.单例模式‌

一.单例模式的定义

单例模式是一种‌创建型设计模式‌,确保一个类‌只有一个实例‌,并提供该实例的‌全局访问点‌。

1.1.核心目标

  • 唯一实例‌:限制类的实例化次数仅一次。
  • 全局访问‌:提供统一的访问入口(通常是静态方法)。

1.2.实现步骤

  • 私有化构造函数 ‌:禁止外部通过new创建实例。
  • 静态私有成员‌:保存类的唯一实例。
  • 静态公有方法 ‌:提供全局访问入口,如getInstance()

.1.3.优点

  • 资源共享‌:如数据库连接池、线程池、配置文件管理器等全局资源。
  • 状态一致性‌:避免多个实例导致状态冲突(如计数器)。
  • 性能优化‌:减少重复创建昂贵对象的开销

二.单例模式的实现方式

2.1.饿汉式实现

  • 特点:类加载时立即创建实例(线程安全)。
  • 优点‌:简单高效,无同步开销。
  • 缺点‌:可能造成资源浪费(即使未使用也会创建实例)。
java 复制代码
/**
 * 饿汉式单例
 */
public class EagerSingleton {
    // 创建一个静态的实例,静态常量,在类加载的时候创建实例
    private static final EagerSingleton instance = new EagerSingleton();
    // 私有化构造方法,使的用者无法通过new关键字创建对象
    private EagerSingleton() {
    }
    //  提供获取实例的方法
    public static EagerSingleton getInstance() {
        return instance;
    }
}

public class demo {
    public static void main(String[] args) {
        EagerSingleton instance = EagerSingleton.getInstance();
        EagerSingleton instance2 = EagerSingleton.getInstance();
        System.out.println(instance == instance2); // true
    }
}

2.2.懒汉式实现

  • 特点 ‌:延迟实例化(首次调用getInstance()时创建)。
  • 优点‌:首次创建后不再同步,兼顾性能与安全。
  • 注意 ‌:必须使用volatile关键字(避免JVM指令重排序导致未初始化完全的错误实例)。
java 复制代码
/**
 * 懒汉式单例普通实现
 */
public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {
    }

    /**
     * 在多线程环境下,多个线程可能同时进入 if (instance == null) 条件块,
     * 并且每个线程都可能执行 new LazySingleton() 语句,从而导致创建多个实例
     * @return
     */
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton(); // 这里可能会有并发问题
        }
        return instance;
    }
}

/**
 * 懒汉式单例‌双重检查锁定实现
 */
public class LazySingleton {
    // volatile 关键字是为了避免指令重排
    private static volatile LazySingleton instance;

    private LazySingleton() {
    }

    /**
     * 在多线程环境下,多个线程可能同时进入 if (instance == null) 条件块,
     * 并且每个线程都可能执行 new LazySingleton() 语句,从而导致创建多个实例
     * 所以需要使用 synchronized 关键字修饰 getInstance() 方法,
     * @return
     */
    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized(LazySingleton.class){
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

2.3.静态内部类实现

  • 特点‌:利用类加载机制保证线程安全,延迟加载。
  • 优势‌:线程安全(JVM保证类加载过程的互斥性)。无同步开销,高效延迟加载。
java 复制代码
/**
 * 静态内部类实现单例模式
 */
public class HolderSingleton {
    private HolderSingleton() {
    }

    /**
     * JVM 确保一个类只会被初始化一次,即使多个线程同时尝试加载该类。
     * 当 HolderSingleton 类被加载时,其内部的 Holder 类并不会立即被加载
     */
    private static class Holder {
        private static final HolderSingleton INSTANCE = new HolderSingleton();
    }

    /**
     * 延迟加载
     * 只有当调用 getInstance() 方法时,才会触发 Holder.INSTANCE 的访问
     * 此时 JVM 才会加载并初始化 Holder 类,并创建 HolderSingleton 实例
     * @return
     */
    public static HolderSingleton getInstance() {
        return Holder.INSTANCE;
    }
}

2.4.枚举实现

  • 特点‌:天然防反射/序列化破坏,简洁安全。
  • 调用方式 ‌:Singleton.INSTANCE.doSomething()
  • 优势‌:绝对单例(JVM保障)。自动处理序列化和反射攻击。
java 复制代码
/**
 * 枚举单例模式
 */
public enum  EnumSingleton {
    //
    /**
     * 枚举实例由JVM在类加载时静态初始化,保证线程安全
     * Java规范禁止通过反射创建枚举实例,避免传统单例被反射攻击的问题
     * 枚举的序列化机制仅保存枚举名称,反序列化时通过valueOf还原原实例,防止生成新对象
     */
    INSTANCE; // 唯一实例

    /**
     *实例方法
     */
    public void whateverMethod() {
        System.out.println("whateverMethod");
    }
}

public static void main(String[] args) {
        //调用
        EnumSingleton.INSTANCE.whateverMethod();
    }

三.应用场景

3.1.初始化开销

  • 轻量级对象 ‌(CPU耗时<50ms,内存<1MB):
    • 适用场景‌:配置管理器、工具类(如字符串处理器)16
    • 饿汉式‌:实例在类加载时创建,启动速度快
  • 重量级对象 ‌(数据库连接、大型缓存):
    • 适用场景‌:数据库连接池、日志系统
    • 静态内部类/DCL‌:延迟加载,避免启动阻塞

3.2.线程安全

  • 高并发场景 ‌:
    • 双重检查锁(DCL) ‌:通过volatile+同步块确保安全(如支付网关)36
    • 枚举‌:JVM保障线程安全(如金融交易引擎)512
  • 低并发场景 ‌:
    • 静态内部类‌:无锁延迟加载(如配置文件读取器)

3.3.防破坏需求

  • 枚举‌:Java规范禁止反射创建枚举实例

3.4.场景化推荐

场景 推荐模式 原因
‌全局配置管理器‌ 饿汉式 配置轻量且启动必用
‌数据库连接池‌ 静态内部类 延迟加载避免启动卡顿,无锁线程安全
‌金融交易核心‌ 枚举 防反射攻击,强一致性要求
‌高频工具类‌ 饿汉式 无状态对象,快速访问
‌第三方服务代理‌ 双重检查锁(DCL) 按需加载+高并发安全(如支付网关)
复制代码
💡 如果本文对你有帮助,点击右上角【订阅专栏】或左上角关注我  
🔔 完整的23中设计模式干货,第一时间推送给你!
相关推荐
SimonKing1 分钟前
拯救大文件上传:一文彻底彻底搞懂秒传、断点续传以及分片上传
java·后端·架构
深栈解码1 分钟前
JUC并发编程 内存布局和对象头
java·后端
北方有星辰zz14 分钟前
数据结构:栈
java·开发语言·数据结构
Seven9716 分钟前
一个static关键字引发的线上故障:深度剖析静态变量与配置热更新的陷阱
java
山野万里__18 分钟前
C++与Java内存共享技术:跨平台与跨语言实现指南
android·java·c++·笔记
风象南19 分钟前
Spring Shell命令行工具开发实战
java·spring boot·后端
Java技术小馆24 分钟前
POST为什么发送两次请求
java·面试·架构
天天摸鱼的java工程师25 分钟前
MySQL表设计实战指南:从业务场景到表结构优化
java·后端·mysql
SimonKing27 分钟前
Java处理PDF就靠它!Apache PDFBox:开源免费的PDF全能王
java·后端·程序员
天天摸鱼的java工程师31 分钟前
Java与AI:从业务场景到代码实现,构建人工客服系统实战
java·后端·面试