创建型模式-单例模式

1.定义

单例模式是一种创建型设计模式,它确保在jvm内存中,一个类的实例只有一个,并且对外提供一个可以访问它的静态方法。核心目的是做资源控制,如数据库连接池,全局配置类等,限制只有一个实例,避免资源浪费和导致资源冲突。

2.实现
  • 饿汉式(最简单,最常用) :类加载到 JVM 时就创建好实例。优点 :绝对线程安全(类加载机制保证),没有锁,响应快。缺点:不管用不用,启动就占内存。
  • 懒汉式(双检锁 DCL) :需要时才创建。使用volatile + synchronized 双重检查
  • 静态内部类(最优雅) :利用 JVM 类加载的懒加载机制。既能实现懒加载,又能保证线程安全,代码比 DCL 简洁。
3.应用场景
  • 日志记录器:全系统使用同一个日志上下文实例,保证日志输出的格式、存储路径和异步刷盘策略统一。
  • 配置管理:全局配置读取。
  • 池化管理:数据库连接池,线程池。
4.优缺点

优点:

  • 可以保证一个类只有一个实例。
  • 获得了一个指向该实例的全局访问节点。

缺点:

  • 违反了单一职责原则。该模式同时解决了两个问题。
  • 单例模式可能掩盖不良设计, 比如程序各组件之间相互了解过多等。
  • 该模式在多线程环境下需要进行特殊处理, 避免多个线程多次创建单例对象。
5.示例代码

饿汉式

java 复制代码
public class SingletonEager {

    // ★ 核心点1:类加载时即完成初始化,由JVM保证线程绝对安全
    // 无需 volatile,因为 JVM 在类加载的初始化阶段(<clinit>() 方法)会保证静态变量的赋值顺序
    // 不存在并发争抢,因此也不存在指令重排带来的可见性问题
    private static final SingletonEager instance = new SingletonEager();

    // 私有构造器,防止外部 new
    private SingletonEager() {
        // 防反射攻击(饿汉式同样适用)
        // 由于类加载时 instance 已经不为 null,反射调用构造器时会被拦截
        if (instance != null) {
            throw new RuntimeException("请勿通过反射破坏单例");
        }
    }

    public static SingletonEager getInstance() {
        // ★ 核心点2:直接返回,无需任何同步检查或判空逻辑
        // 调用时毫无性能开销,但若从未使用,资源依然被加载(类加载时即占用内存)
        return instance;
    }
}

懒汉式(双重检查锁)

java 复制代码
public class SingletonDCL {

    // ★ 核心点1:必须加 volatile,防止指令重排序
    // 防止 instance = new SingletonDCL() 时,赋值操作先于对象初始化完成,导致其他线程拿到半成品对象
    private static volatile SingletonDCL instance;

    // 私有构造器,防止外部 new
    private SingletonDCL() {
        // 防反射攻击(可选,但加分项)
        if (instance != null) {
            throw new RuntimeException("请勿通过反射破坏单例");
        }
    }

    public static SingletonDCL getInstance() {
        // 第一重检查:避免不必要的同步(性能优化)
        if (instance == null) {
            // ★ 核心点2:类锁,保证线程安全
            synchronized (SingletonDCL.class) {
                // 第二重检查:防止在等待锁的过程中,被其他线程抢先创建了实例
                if (instance == null) {
                    instance = new SingletonDCL();
                }
            }
        }
        return instance;
    }
}

静态内部类:

java 复制代码
public class SingletonHolder {

    // 私有构造器
    private SingletonHolder() {
        // 防反射攻击
        if (Holder.INSTANCE != null) {
            throw new RuntimeException("请勿通过反射破坏单例");
        }
    }

    // ★ 核心点:利用 JVM 类加载机制保证线程安全,且实现懒加载
    // 只有调用 getInstance() 时,Holder 类才会被加载,INSTANCE 才会初始化
    private static class Holder {
        private static final SingletonHolder INSTANCE = new SingletonHolder();
    }

    public static SingletonHolder getInstance() {
        return Holder.INSTANCE;
    }
}
相关推荐
rannn_11120 小时前
【力扣hot100】链表专题|160、206、234、141、142
java·算法·leetcode·链表·面试·开发
IKUN家族1 天前
Spring IoC&DI
java·spring·rpc
山荷枝1 天前
03-框架--Spring
java·后端·spring
ChaHae-In1 天前
SpringBoot统一功能处理
java·spring boot·后端
coder!mq1 天前
说几个常见的语法糖?
java·开发语言·算法
gugucoding1 天前
38. 【Java】Stream API(下):高级操作与性能
java·开发语言
心平气和量大福大1 天前
android-实例-蒲公英-更新与安装-5-签名与生成APK
android·java·开发语言
952361 天前
Spring-cloud配置中心
java·spring·spring cloud·微服务
ydd1001001 天前
寻找两个正序数组的中位数 Java 题解,二分分割详解
java·开发语言
真上帝的左手1 天前
10. 软件设计&架构-Spring Security 7 整合CAS SSO 单点登录
java·spring·架构·sso