创建型模式-单例模式

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;
    }
}
相关推荐
吴声子夜歌21 分钟前
Guava——散列
java·guava
用户31268748772022 分钟前
AQS 到底怎么排队的?CLH 队列、state 与条件变量全链路拆解
java
Json____28 分钟前
springboot开发高校选课管理系统:从零构建前后端分离的全栈实践
java·spring boot·后端·毕业设计·毕设·wwwoop.com
xcl092538 分钟前
民宿预约系统开发实战:从需求分析到上线部署全流程解析
java·spring boot
步行cgn1 小时前
为何以继承方式引入SpringBoot
java·spring boot·后端
CoderYanger1 小时前
A.每日一题:1140. 石子游戏 II
java·程序人生·算法·leetcode·游戏·职场和发展·深度优先
禾高网络1 小时前
养老系统开发:背景、架构与养老行业展望
java·大数据·人工智能·小程序·架构
CCYe、1 小时前
新模型上线、旧模型下线:企业AI网关如何管住模型版本
java·网络·数据库·人工智能
风筝在晴天搁浅1 小时前
解题代码清爽版
java·开发语言
NeverFear7921 小时前
【黑马点评】短信登录
java·redis·tomcat·intellij-idea