设计模式之单例模式

简介

单例模式是一种设计模式,核心思想是确保一个类只有一个实例,私有化类的构造方法(防止外部直接创建)并提供一个全局访问点,一个实例进行复用可以避免频繁的创建和销毁对象,是非常简单且在面试时高频出现的设计模式,单例模式分为饿汉模式和懒汉模式,本篇就来盘一盘

饿汉模式:

顾名思义,是指该对象的实例非常迫切的被实例化,具体有多早呢,使用static关键字修饰,使得该实例在类加载时就一起被创建,获取实例很快并且不会有线程安全问题,不过是正是由于在类加载时实例化,如果对象的数据较多,则会影响类加载的时间。

懒汉模式:

是指不着急实例化对象,在首次需要的时候才会被实例化,不过这种最简易的懒汉单例模式在多线程下会有线程安全问题,例如多个线程同时访问getDemo()方法,都会认为还没有创建实例,从而创建出多个实例,这就不是单例模式了

线程安全的懒汉模式:

直接上完全体版本,以多线程并发视角打开这张图,首次检查,多个线程同时判断未创建实例,进入到synchronized修饰的代码快,此时只有一个线程能够进入,其他线程都会被阻塞,当唯一进入的线程创建好实例后执行结束释放锁时,其他被阻塞的线程依次获取到锁进入,再次判断实例是否被创建,前人栽树后人乘凉,此时已经有实例了,就会直接返回实例 ,不过不排除有那么一点点点概率发生前面的线程创建实例但内存刚好没有刷新,从而使后面的线程判断到还是没有创建实例,导致变成多例,于是在用于存储实例的变量上加上volatile关键字,保证线程对该变量的修改及时刷新到主内存中,volatile关键字详见>>>>>volatile关键字的作用(拿着demo自己试试)

java 复制代码
public class Demo {
    //静态私有成员变量,用于存储唯一的实例,使用volatile修饰保证其他线程的更新能被刷新到主内存
    private static volatile Demo instance ;

    //私有化构造方法,防止外部直接创建
    private Demo() {

    }
    //全局唯一访问点
    public static Demo getDemo() {
        // 第一次检查:如果实例尚未创建则创建
        if (null == instance) {
            //加锁,保证同时只有一个线程进入创建实例,可能会有多个线程同时判断到没有创建实例,从而都被阻塞在这里
            synchronized (Demo.class) {
                //再次校验,以免多个线程在锁释放时直接创建实例,这便是双重检验
                if (null == instance) {
                    instance = new Demo();
                }
            }
        }
        return instance;
    }

    public static void main(String[] args) {
        Demo demoOne = Demo.getDemo();
        Demo demoTwo = Demo.getDemo();

        System.out.println(demoOne.equals(demoTwo));
    }
}

其他实现方式:

1.枚举

枚举就是单例模式,实现非常简洁,其构造方法默认就是私有的,并且枚举的实例也是在类加载时就已经创建,我们可以通过以下例子来玩一玩

2.静态内部类
这个厉害了,实现简单,支持懒加载并且线程安全(还有高手)

类加载的线程安全机制 :

JVM在类加载过程中,特别是在初始化阶段,会自动获取一个锁,确保同一个类在多线程环境下只会被加载和初始化一次
静态内部类的延迟加载特性:

在静态内部类实现中,单例实例是通过静态内部类的静态成员持有的,外部类被加载时,静态内部类并不会立即被加载和初始化,只有在首次调用getInstance()方法时,静态内部类才会被加载

总结:

1.单例模式就是确保一个类只有一个实例,私有化类的构造方法并提供一个全局访问点,避免对象频繁创建和销毁

2.分为饿汉模式和懒汉模式,常规懒汉模式有线程安全问题,需要双重检验加锁

3.枚举也是饿汉单例模式,静态内部类实现单例模式既可以懒加载又是线程安全的


上一篇 >>>>> volatile关键字的作用(拿着demo自己试试)

看千遍想万遍,还得动手练一练,量变才能产生质变

相关推荐
瑞克-桑切斯11 分钟前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
海的透彻5 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
code2cat5 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
后台模板学习5 小时前
大模型 Prompt 工程在电商订单系统中的踩坑记录
java·python·prompt
w_zero_one6 小时前
算法--构造
java·数据结构·算法
SL_staff6 小时前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
SL_staff7 小时前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
Mikko77 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
.Bryce.7 小时前
从零到一开发技术名词大全:从需求分析到 AI Agent 工程
java·网络·人工智能·agent·需求分析·agent评测
SL_staff7 小时前
JVS-APS的7个刚性约束设计:从无限产能幻觉到可执行排产的工程实践
java·spring cloud·全栈