【谈一谈】: 我们工作中的单例模式有哪些写法?

单例模式的多种写法

我们要实现一个单例,首先最重要的是什么?

当然是把构造函数私有化,变成private类型,(为啥? 单例单例,如果谁都能通过构造函数创建对象,还叫单例吗?是不~)

嗯~我们构造函数私有化后,我们应该操作啥呢?

接着我们需要提供一个方法,这个方法要保证初始化有且仅初始化一个单例对象!~

Okk~,请再看看我们的标题,思考下,单例模式有哪几种写法呢?工作中我们最常用的是哪些呢?

好了,别想了,我们一起看答案

单例模式有五种模式: 1.懒汉,2.饿汉,3.枚举,4.静态内部类,5.双重检验锁

最常用的嘛: 当然两个单身汉啦: 饿汉懒汉了(和我一样,都是狗~哈哈哈)


上述的说明是我们对单例模式整体有了个大概得了解,你说:这不行啊!我还是*心虚*,因为只是**纸上谈兵**,别急嘛,我们这就**此事躬行**!


万变不离其宗:

本文总纲图:

在这里插入图片描述

下面是五中单例模式的代码实现,(还是那句话~看不懂,我们就敲,若一遍不行,就两遍,Practice makes perfect!)

还有在敲下面的代码之前,我们思考下(也是一道面试题)

为啥单例模式要使用staticfinal进行声明呢???(后面我会给解答,但先思考下,会吸收事半功倍~哈哈哈)

1.懒汉模式

为啥叫懒汉模式呢?如它的名字一样,创建对象只有进程用到的时候,才进行创建

换句话说: 被动创建,比如工作,老板叫我干我就做,没叫我时,我就佛系摸鱼

具体代码:

package com.design_patterns;
/*** <p>* 描述:  懒汉单例$      <br>* <p>* 需求信息: 【需求ID与需求标题】【客户名称】 <br>** @author aristo* @date 2024/2/21 10:51*/
public class LazyMan {public  static  LazyMan instance;   //构造函数私有化private LazyMan(){};//获取对象public  static synchronized LazyMan getInstance(){//发现对象为空时,创建对象;否则直接返回if(instance==null){instance=new LazyMan();}return instance;}
}

2.饿汉模式

此模式就和懒汉就相反了,有种忧患意识,类似悲观锁的算法设计思想

啥意思?就是在程序启动时,我就立即将单例对象给创建出来—具体我们看代码就一幕了然了

package com.design_patterns;
/*** <p>* 描述:  饿汉模式$      <br>* <p>* @author zf* @date 2024/2/21 14:31*/
public class HungryModel {//注意看: 我们这里是直接就创建对象了   这里面的static和final思考下为啥用(不用行不行呢?)public  static  final   HungryModel instance=new HungryModel();private   HungryModel  (){};public  static  HungryModel getInstance(){//这里我们就直接返回return instance;}
}

3.枚举单例模式

写到枚举单例模式,我们在这也思考一道题目:

为什么枚举是最好的单例模式?? (哈哈哈!你别吐槽–这博主真是的,我就看个博文,咋又叫我思考噻!没错,因为我们要的是看一篇顶三篇!!!)

这我会单独写一篇文章描述,这里插个眼,标记下~哈哈哈

代码实现示例:

package com.design_patterns;/*** 描述:  单例模式---枚举方式      <br>* @author zf* @date 2024/2/21 16:14*/
public enum EnumSingleton {INSTANCE;public void  testMethod(){}
}

4.静态内部类单例模式

所谓的静态内部类单例模式,我们可以看到在创建对象时,我们是在类中定义一个静态内部类(很关键!!!) 其实你自己敲一遍就拨开其真面目了!~

详细解说嘛,我推荐你敲一遍,就知庐山真面目了~(你说,那我敲一遍还不懂咋整啊?直接评论区@轰炸我)

package com.design_patterns;/*** 描述:  静态内部类单例模式      <br>* @author zf* @date 2024/2/21 16:18*/
public class StaticInnerClassSingleton {//所谓的静态内部类单例模式,我们可以看到在创建对象时,我们是在类中定义一个静态内部类(很关键!!!!)   其实你自己敲一遍就拨开其真面目了!~private static class SingletonHolder{private static final StaticInnerClassSingleton INSTANCE=new StaticInnerClassSingleton();}private StaticInnerClassSingleton(){};public static final StaticInnerClassSingleton getInstance(){return SingletonHolder.INSTANCE;}}

5.双重检验锁单例模式

顾名思义: 就是通过两把锁检测把关后,我们创建对象,啥好处?安全性高

对于代码中的volatile,再思考一下,我们为啥要加??

package com.design_patterns;/*** <p>* 描述:  双重检验锁单例模式      <br>* <p>* 需求信息: 【需求ID与需求标题】【客户名称】 <br>** @author zf* @date 2024/2/21 16:29*/
public class DoubleLockSingleton {//好了,别想了,我解答下: 使用volatile:  防止指令重排!!!!!(面试官问你,就抛给他这句话,完事~)private volatile static DoubleLockSingleton doubleLockSingleton;//私有化private DoubleLockSingleton(){};public static DoubleLockSingleton getInstance(){//第一遍检验if(doubleLockSingleton==null){synchronized (DoubleLockSingleton.class){//再次检验if(doubleLockSingleton==null){doubleLockSingleton=new DoubleLockSingleton();}}}return doubleLockSingleton;}
}

【解答】单例模式为啥使用staticfinal关键字???

回顾我们一开始说的问题,我来解答下哈!耐心看看嘛,绝对夯实基础,出门还可**吹牛逼**!嘿嘿

1.static的特殊含义

static可以保证在一个线程未使用其他同步机制的情况下总是可以读到一个类的静态变量的初始值!!!(这句话建议读三遍,真的诠释了静态的真谛)

上面也许不好理解,但我们首先应该知道:static变量是随着类被初次访问而初始化的。

比如在多线程的环境中,需要保证一个变量在线程中的可见性是需要对内存做一些操作指令的。

这么说不怎么明白吧? 举个例子:(可以不看哈,纯粹为了加深理解)

当两个线程A,B对一个共享变量进行操作的时候,

  • 首先是把内存中的数据加载进各自的处理器中,然后在放入各自的寄存器
  • A中更新共享变量的时候,首先会被放入写缓存器中,然后再写入高速缓存中,最后是放进内存中,每个处理器都有各自的写缓存器高速缓存
  • 所以在一个时间点,线程B读取的共享变量值并不是A更新的那一个,仍然很有可能是一个旧值。(类似于脏读)
  • 对于这个旧值怎么理解呢?()
    • 在计算机系统设计中,为了保证变量的可见性,有一种协议叫做缓存一致性协议
    • 这个协议的作用我简单说明下:不同的处理器可以读取对方高速缓存中的值。这时我们要保证可见性只需要一步,就是当共享变量被更新的时候,原子性保证把值写入高速缓存中就可以了,
    • 对于volatile的实现方式也是基于这种思想。
  • 那么static变量所做的事情就是,在某个线程调用的时候,就写入内存中这个值,保证内存中必然有这个值的存在,
  • 注意static并不能保证多线程之后操作的可见性

2.final

我们都知道,final修饰的变量值不会改变;但是在多线程的环境中,它还会保证两点

  1. 其他线程所看到的final字段必然是初始化完毕的。
  2. final修饰的变量不会被程序重排序。

综上所述:

static保证了变量的初始值,final保证了不被JIT编译器重排序。

对于一个单例模式来说,它所在的类在被引用的时候,static会保证它被初始化完毕,且是所有线程所见的初始化final保证了实例初始化过程的顺寻性。两者结合保证了这个实例创建的唯一性。

完结

好了,各位优秀的同仁们,学废了没?哈哈哈!~是不是又学到了呢?

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

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

相关文章

数据脱敏(六)脱敏算法-加密算法

脱敏算法篇使用阿里云数据脱敏算法为模板,使用算子平台快速搭建流程来展示数据 "加密脱敏"是一种数据处理技术&#xff0c;主要用于保护个人隐私和数据安全。它通过将敏感信息&#xff08;如姓名、身份证号、电话号码等&#xff09;进行加密处理&#xff0c;使其无法…

阿里同学聊测试开发与测试平台

在一线大厂&#xff0c;没有测试这个岗位&#xff0c;只有测开这个岗位&#xff0c;即使是做业务测试&#xff0c;那么你的title也是测开。 所以想聊一聊测开的看法&#xff0c;但不代表这是正确的看法&#xff0c;仅供参考。 没来阿里之前我对测开的看法 一直以为专职做自动…

DIcom调试Planar configuration

最近和CBCT组同事调dicom图像 这边得图像模块老不兼容对方得dicom文件。 vtk兼容&#xff0c;自己写得原生解析不兼容。 给对方调好了格式&#xff0c;下次生成文件还会有错。 简单记录下&#xff0c;日后备查。 今天对方又加了 个字段&#xff1a;Planar configuration 查…

【常识】大数据设计基础知识

底层存储&#xff1a;hadoop&#xff08;hdfsmapreduce&#xff09; Hadoop已经有十几年的历史&#xff0c;它是大数据领域的存储基石&#xff0c;HDFS目前仍然没有成熟替代品;MapR 文件系统在业内已经具有一定知名度了&#xff0c;不仅 MapR 宣布它自己的文件系统比 HDFS 快2-…

【Unity】【VRTK】【VR开发】同时保持高效打包和调试的VRTK项目设置方式

【背景】 开发功能时希望能够快速调试&#xff0c;在Preview和开发编辑器间流畅切换。后期又希望快速打包到目标安卓平台&#xff0c;感受头盔内部的画面和操作效果。麻烦在于&#xff0c;这两者往往不是明确区分的&#xff0c;很可能一会儿只是想快速验证一下某些功能动作&am…

二进制搭建 Kubernetes

实验流程 k8s集群master01&#xff1a;192.168.75.10 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02&#xff1a;192.168.80.20 k8s集群node01&#xff1a;192.168.75.20 kubelet kube-proxy docker k8s集群node02&#xff1a;192.168.…

Out of memory,realloc failed

git config --global http.postBuffer 1048576000

多线程相关(2)

线程池 构造函数处理过程拒绝策略JDK 内置的拒绝策略 Executors类实现线程池线程池大小设置 通过复用已创建的线程&#xff0c;降低资源损耗、线程可以直接处理队列中的任务加快响应速度、同时便于统一监控和管理。 构造函数 /*** 线程池构造函数7大参数*/ public ThreadPoolE…

opencv鼠标操作与响应

//鼠标事件 Point sp(-1, -1); Point ep(-1, -1); Mat temp; static void on_draw(int event, int x, int y, int flags, void *userdata) {Mat image *((Mat*)userdata);if (event EVENT_LBUTTONDOWN) {sp.x x;sp.y y;std::cout << "start point:"<<…

动态住宅IP代理是什么意思,与静态住宅IP代理的区别和比较

动态住宅IP代理是一种不断变化的IP地址解决方案&#xff0c;用于提高在线安全性、绕过地理限制并进行高级数据挖掘。与静态住宅IP代理相比&#xff0c;动态IP提供更高的匿名性和灵活性&#xff0c;但也有其独特的局限性和成本。我们旨在为您提供一个全面的视角&#xff0c;让您…

LocalSend跨设备传输文件传输协议 v2

LocalSend仓库地址&#xff1a;GitHub - localsend/localsend: An open-source cross-platform alternative to AirDrop LocalSend 协议 v2 English | 简体中文 主要为了实现一个不依赖于任何外部服务器的简单 REST 协议。 因为计算机网络比较复杂&#xff0c;因此我们不能假…

Java实现假日旅社管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统介绍2.2 QA 问答 三、系统展示四、核心代码4.1 查询民宿4.2 新增民宿评论4.3 查询民宿新闻4.4 新建民宿预订单4.5 查询我的民宿预订单 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的假日旅社…

第十七届“挑战杯”广东大学生课外学术科技作品比赛感想

博主曾在2023年参加了第十七届“挑战杯”广东大学生课外学术科技作品比赛&#xff0c;也就是人们俗称的大挑&#xff0c;在团队赛里面含金量应该是排在第一档的了&#xff0c;当初我们有幸作为学校唯一一支科技创新B类进入到线下答辩&#xff0c;线下答辩就是区分银奖和金奖和特…

恩智浦MCX A系列:开启工程师的无限创造潜力 | 百能云芯

恩智浦半导体&#xff08;NXP&#xff09;最近宣布推出旗下MCX产品组合中的全新成员——通用A系列的首批产品MCX A14x和MCX A15x&#xff0c;现已正式上市。这一系列的微控制器&#xff08;MCU&#xff09;不仅性价比高、使用便捷、体积小巧&#xff0c;而且还旨在为工程师们打…

分布式版本控制系统 Git

目录 一、Git简介 二、Git历史 三、安装git 1.准备环境 2.Yum安装Git 四、初次运行 Git 前的配置 命令集 实例&#xff1a; 五、Git命令常规操作 六、获取 Git 仓库&#xff08;初始化仓库&#xff09; 创建裸库 实例 &#xff1a; 创建本地库 一、Git简介 官网&…

opencv-python安装失败问题解决

用pip install opencv-python命令终端中出现如下报错&#xff1a; 解决方法&#xff0c;换一个源&#xff0c;输入&#xff1a; pip install opencv-python -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com运行之后即可安装成功&#xff1a;

浅谈加密算法(对称加密、非对称加密、混合加密、数字签名、哈希函数)

1、对称加密 对称加密只有一个密钥&#xff0c;直接使用这一个密钥对信息进行加密或解密。这样子就使得对称加密解密十分高效&#xff0c;计算量也相较于非对称加密小很多&#xff0c;适合有大量数据的场合。 密钥只有一个且他一定不能泄漏。由此分发密钥&#xff0c;讲这个密钥…

SQL 练习题目(入门级)

今天发现了一个练习SQL的网站--牛客网。里面题目挺多的&#xff0c;按照入门、简单、中等、困难进行了分类&#xff0c;可以直接在线输入SQL语句验证是否正确&#xff0c;并且提供了测试表的创建语句&#xff0c;也可以方便自己拓展练习&#xff0c;感觉还是很不错的一个网站&a…

ChromeDriver | 谷歌浏览器驱动下载地址 及 浏览器版本禁止更新

在使用selenoum时&#xff0c;需要chrome浏览器的版本和chrome浏览器驱动的版本一致匹配&#xff0c;才能进行自动化测试 一、ChromeDriver驱动镜像网址 国内可以搜到的谷歌浏览器下载地址里面最新的驱动器只有114版本的CNPM Binaries Mirror 在其他博主那找到了最新版本12X的…

【PX4SimulinkGazebo联合仿真】在Simulink中使用ROS2控制无人机沿自定义圆形轨迹飞行并在Gazebo中可视化

在Simulink中使用ROS2控制无人机沿自定义圆形轨迹飞行并在Gazebo中可视化 系统架构Matlab官方例程Control a Simulated UAV Using ROS 2 and PX4 Bridge运行所需的环境配置PX4&Simulink&Gazebo联合仿真实现方法建立Simulink模型并完成基本配置整体框架各子系统实现原理…