【编码魔法师系列_构建型2.2】单例模式「懒汉式」(Singleton Pattern)

news2025/1/10 13:17:00

在这里插入图片描述

学会设计模式,你就可以像拥有魔法一样,在开发过程中解决一些复杂的问题。设计模式是由经验丰富的开发者们(GoF)凝聚出来的最佳实践,可以提高代码的可读性、可维护性和可重用性,从而让我们的开发效率更高。通过不断的练习和实践,掌握其中的奥妙,选择合适的设计模式,能为我们的项目增加一丝神奇的魔力。

文章目录

  • 实例:
  • 目的:
  • 适用场景:
  • 优点:
  • 弊端:
  • 类图:
  • 框架用到的地方:
  • Coding:
    • 线程不安全
      • 将getInstance()方法进行改造
      • 测试:
      • 测试结果:
    • 双检锁方式——线程安全
      • 改造getinstance()方法
      • 测试
      • 测试结果
    • 利用枚举
    • 将饿汉和懒汉结合:
      • 测试
      • 测试结果:

实例:

模拟多线程下单例模式(懒汉式)初始化对象

目的:

使得一个全局使用的类不会被频繁地创建与销毁。

适用场景:

1、需要频繁地进行创建和销毁的对象
2、创建对象耗时或耗费资源过多,但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)。

优点:

在类加载时不初始化,使用时才创建,因此类加载速度快,节约资源

弊端:

运行时获取对象的速度慢。在多线程的场景下,为了实现线程安全,要付出额外代价

类图:

在这里插入图片描述

框架用到的地方:

java.lang.Runtime;spring依赖注入

Coding:

线程不安全

/**
 * 线程不安全
 */
public class LazySingleton {
    private static LazySingleton instance = null;

    private LazySingleton() {
    }

    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }

    public void showMsg() {
        System.out.println("This is LazySingleton!");
    }
}

这种方式,不能保证线程安全,接下来我们模拟一个多线程场景:

将getInstance()方法进行改造

public static LazySingleton getInstance() {
    if (instance == null) {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        instance = new LazySingleton();
    }
    return instance;
}

测试:

@Test
public void Test1() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(LazySingleton.getInstance());
        }
    }).start();
    System.out.println(LazySingleton.getInstance());
}

测试结果:

LazySingleton@48cf768c
LazySingleton@47382356

上述代码之所以说它“线程不安全”是因为:在多个线程同时调用getInstance()方法的时候,大概率会同时创建多个实例,所以此时我们不得不加上“synchronized”来避免这个问题,但是我们可以很快的发现:假设多个线程都在竞争锁,又会严重影响并发性能,所以我们只需要在竞争锁之前先判断一次实例是否此时为null,就可以减少不必要的抢锁动作,至此,我们就完成了“双检锁方式”,这是一种比较好的单例实现模式。

双检锁方式——线程安全

/**
 * 双检锁方式
 * 线程安全
 */
public class LazySingletonV2 {
    private static LazySingletonV2 instance = null;

    private LazySingletonV2() {
    }

    public static LazySingletonV2 getInstance() {
        //如果instance不为null,无需抢锁,返回instance即可
        if (instance == null) {
            //避免多线程调用时,创建多个instance
            synchronized (LazySingletonV2.class) {
                //抢到锁的线程判断是否为null
                if (instance == null) {
                    instance = new LazySingletonV2();
                }
            }
        }
        return instance;
    }

    public void showMsg() {
        System.out.println("This is LazySingletonV2!");
    }
}

synchronized:等一个人执行完毕,才会继续执行
模仿上面的实验,我们再做一次:

改造getinstance()方法

public static LazySingletonV2 getInstance() {
    //如果instance不为null,无需抢锁,返回instance即可
    if (instance == null) {
        //避免多线程调用时,创建多个instance≈
        synchronized (LazySingletonV2.class) {
            try {
                //模拟创建对象之前做的准备工作
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            //抢到锁的线程判断是否为null
            if (instance == null) {
                instance = new LazySingletonV2();
            }
        }
    }
    return instance;
}

测试

@Test
public void Test2() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(LazySingletonV2.getInstance());
        }
    }).start();
    System.out.println(LazySingletonV2.getInstance());
}

测试结果

LazySingletonV2@5a420d92
LazySingletonV2@5a420d92

当然我们也可以直接利用Java内置的“枚举”来实现单例模式:因为枚举类型是线程安全的,并且只会装载一次。

利用枚举

/**
 * 利用枚举
 */
public enum LazySingletonV3 {

    INSTANCE;

    private String Msg = "This is LazySingletonV3!";

    public String getMsg() {
        return Msg;
    }

    public void setMsg(String msg) {
        Msg = msg;
    }
}

将饿汉和懒汉结合:

/**
 * 饿汉,懒汉结合
 */
public class LazySingletonV4 {

    public static class InnerHolder{
        private static LazySingletonV4 instance = new LazySingletonV4();
    }

    private LazySingletonV4() {
        System.out.println("LazySingletonV4"+"create");
    }

    public static LazySingletonV4 getInstance() {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        return InnerHolder.instance;
    }

    public void showMsg() {
        System.out.println("This is LazySingleton!");
    }
}

测试

@Test
public void Test4() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println(LazySingletonV4.getInstance());
        }
    }).start();
    System.out.println(LazySingletonV4.getInstance());
}

测试结果:

LazySingletonV4  getInstance
LazySingletonV4  getInstance
LazySingletonV4  create
LazySingletonV4@48cf768c
LazySingletonV4@48cf768c

从打印语句可以看出:输出了两次getInstance之后才输出了create,所以只有使用到这个内部类的时候才会被创建
且由java虚拟机创建,是单线程执行,保证了线程安全
这种方式结合了懒汉模式和饿汉模式的优点:高效解决了懒汉模式的线程不安全的问题,同时也不会像饿汉模式一样浪费资源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1175818.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何整合项目计划与执行,看看这篇就够了

项目中的挑战,如同生活中的问题,无处不在。常言道:“家家有本难念的经”,面对这些问题,我们应采取积极的态度,通过有效的沟通,让家人了解我们的困境,这样许多问题就能在无形中得到解…

虚拟机Linux-Centos系统网络配置常用命令+Docker 的常用命令

目录 1、虚拟机Linux-Centos系统网络配置常用命令2、Docker 的常用命令2.1 安装docker步骤命令2.2 在docker容器中安装和运行mysql 1、虚拟机Linux-Centos系统网络配置常用命令 进入网络配置文件目录 cd /etc/sysconfig/network-scripts/用 ls 命令查看文件:ls …

基于SpringAOP实现自定义接口权限控制

文章目录 一、接口鉴权方案分析1、接口鉴权方案2、角色分配权限树 二、编码实战1、定义权限树与常用方法2、自定义AOP注解3、AOP切面类(也可以用拦截器实现)4、测试一下 一、接口鉴权方案分析 1、接口鉴权方案 目前大部分接口鉴权方案,一般…

Ps:色域警告

Ps菜单:视图/色域警告 View/Gamut Warning 色域警告 Gamut Warning可以依据要模拟的输出设备的色彩能力来确定图像上的哪些颜色可能会超出该设备的色彩范围。 “色域警告”只能起到提示的作用,启用(勾选)以后,画面上的…

清华软院2024届推免拟录取名单

名单 直博生 硕士生 分析 清华软院2024届共录取推免硕士生68人,其中 专硕085405软件工程 59人,学硕083500软件工程9人;推免直博生 15人 和贵系相比难度要低很多哦! 欢迎关注我的公众号 “程序员小风学长”,会定期进…

【工具】Github统计代码行数工具推荐(VScode插件、兼容任何平台、不用下载安装包)

需求: 1)被要求统计代码行数; 2)不想打开Linux,懒得下载Windows版本GitStats; 3)打开了Linux但也不记得find命令行怎么用; 4)打开了Linux,装好了Gitstats但自…

基于金枪鱼群算法的无人机航迹规划-附代码

基于金枪鱼群算法的无人机航迹规划 文章目录 基于金枪鱼群算法的无人机航迹规划1.金枪鱼群搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要:本文主要介绍利用金枪鱼群算法来优化无人机航迹规划。 …

唐顿庄园的AI圣诞设计(ideogram.ai )

唐顿庄园是一部经典的英国历史剧,讲述了 Crawley 家族在 20 世纪初生活的故事。该剧以其精美的服装、场景和道具而闻名,因此它是圣诞装饰的绝佳灵感。 在本文中,我们将使用 ideogram.ai 创建一个 Downton Abbey 圣诞设计。ideogram.ai 是一个…

图解系列--查漏补缺

1. L2转发,L3转发 网络传输中,每个节点会根据分组数据的地址信息,来判断该报文应该由哪个网卡发送出去。为此,各个地址会参考一个发出接口列表。在这一点上 MAC 寻 址与IP 寻址是一样的。只不过MAC 寻址中所参考的这张表叫做地址…

Activiz.NET.x64无法显示点云

将Activiz.NET.x64 nuget包拉下后,无法显示点云,或者报错,需要检测几个要素: 1.活动平台是否60位, 2.显示控件是否正常加载, 3.点云是否正确, 4.如果是.netcore,还需要自己将Activiz…

docker容器的日志占满磁盘空间处理办法

1、输入命令: du -d1 -h /var/lib/docker/containers | sort -h 日志文件高达几十个G,进入每个容器的路径: cd /var/lib/docker/containers/b35751c633bdd3b268769675fb145a8ade8d9c8b5df45d28a596274447913dd4 清空名为"容器id-json…

改进YOLO系列:12.Repulsion损失函数【遮挡】

1. RepLoss论文 物体遮挡问题可以分为类内遮挡和类间遮挡两种情况。类间遮挡产生于扎堆的同类物体,也被称为密集遮挡(crowd occlusion)。Repulsion损失函数由三个部分构成,yolov5样本匹配,得到的目标框和预测框-一对应第一部分主要作用:预测目标框吸引IOU最大的真实目标框,…

第十章《搞懂算法:支持向量机是怎么回事》笔记

支持向量机(Support Vector Machine,SVM )主要用于分类问题的处理。 10.1 SVM有什么用 SVM 的分类效果很 好,适用范围也较广,但模型的可解释性较为一般。 SVM 根据线性可分的程度不同,可以分为 3 类:线性可分 SVM、线性 SVM 和…

做一个交友app多少钱,交友app开发成本大揭秘

在如今社交化的时代,交友app正日益成为人们拓展社交圈、寻找真爱或结交新朋友的首选平台。随着用户需求的不断增长,许多有远见的创业者都渴望开发一款成功的交友app。不过,要想开发一款具备优质功能和用户体验的交友app,需要投入多…

在 Windows 上安装 Java指南

文章目录 在 Windows 上安装 Java指南1. 下载安装包2. 安装到本机3. 配置环境变量3.1 打开高级系统设置3.5 验证环境变量 参考文献 在 Windows 上安装 Java指南 1. 下载安装包 我们首先打开Oracle官网的 JDK 下载地址,找到 Java SE 15 版块,点击 JDK D…

【深度学习】pytorch——神经网络工具箱nn

笔记为自我总结整理的学习笔记,若有错误欢迎指出哟~ 深度学习专栏链接: http://t.csdnimg.cn/dscW7 pytorch——神经网络工具箱nn 简介nn.Modulenn.Module实现全连接层nn.Module实现多层感知机 常用神经网络层图像相关层卷积层(Conv&#xff…

前端数据加解密:保护敏感信息的关键

前言 如今,数据安全和隐私保护变得至关重要。本文旨在引领大家探索前端数据加密与解密的基本概念,并介绍常用的加密算法,让大家深入了解数据加解密的世界,探究其背后的原理、最佳实践和常见应用场景。 前端主流加密方式 对称加密 …

【Nuxt】在 Nuxt3 中使用 Element Plus

安装 Element Plus 和图标库 pnpm add element-plus --save pnpm add element-plus/icons-vue安装 Nuxt Element Plus 模块 pnpm add element-plus/nuxt -D配置 Nuxt 项目 在 nuxt.config.ts 中配置 // https://nuxt.com/docs/api/configuration/nuxt-config export defaul…

聚观早报 |小米CarWith启动兼容测试;「天工」大模型开放

【聚观365】11月6日消息 小米CarWith启动兼容测试 「天工」大模型开放 邮政快递揽收超20亿件 华为Mate 60 Pro开启预约申购 VERTU持续探索前沿科技 小米CarWith启动兼容测试 小米CarWith是打造“人车家生态”中不可或缺的一环,在最新升级的2.0版本中&#xff…

VMware Ubuntu 共享文件夹

VMware Ubuntu 共享文件夹 flyfish 物理机配置 Network Adapter设置 此处设置为NAT Shared Folders设置 虚拟机配置 vmware-hgfsclient sudo vmhgfs-fuse .host:/ /mnt -o nonempty -o allow_other 或者 sudo vmhgfs-fuse .host:/ /mnt/ -o allow_other第一行命令是查看共…