创建型模式-单例模式

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;
    }
}
相关推荐
weixin_BYSJ19872 小时前
「课设设计」springboot校园超市助购系统26449 (附源码)
java·javascript·spring boot·python·django·flask·php
栋***t2 小时前
从“纸质试卷”到“AI智能组卷”,麦塔在线考试系统如何重构出题逻辑?
java·大数据·人工智能·算法·重构
CHANG_THE_WORLD2 小时前
深入理解递归:从函数调用到调用栈的完整执行过程
java·开发语言·算法
xexpertS2 小时前
CI/CD 熔断机制:如何通过编排级熔断器提升开发者效率
java·linux·运维
zy happy2 小时前
VMware虚拟机添加新的硬盘
java·linux·jvm·docker
AI人工智能+电脑小能手3 小时前
【大白话说Java面试题 第192题】【08_Kafka篇】第8题:死信队列是什么?延时队列是什么?
java·kafka·消息队列·死信队列·延时队列
meng半颗糖3 小时前
3.Java流程控制语句
java·开发语言·intellij-idea
大模型码小白3 小时前
企业级检索增强后端集成:Java 服务如何管理知识库版本
java·服务器·开发语言·人工智能·python·microsoft
用户6169182299933 小时前
记录一次死锁检测
java