当前位置: 首页 > news >正文

Java之单例模式

目录

一.上节内容

1.什么是线程安全

2.线程不安全的原因

3.JMM(Java内存模型)

4.synchronized锁

5.锁对象

6.volatile关键字

7.wait()和notify()

8.Java中线程安全的类

二.单例模式

1.什么是单例

2.怎么设计一个单例

1.口头约定

2.使用编程语言的特性

三.饿汉模式

四.懒汉模式

1.单线程下的懒汉模式

2.多线程下的懒汉模式

3.分析线程不安全的原因

4.加锁解决这个问题

5.双重检查锁

6.加volatile优化(单例懒汉模式最终版)


一.上节内容

上节内容指路:Java之线程安全

1.什么是线程安全

在多线程环境下程序运行的结果与单线程环境下程序运行的结果不一样(不达预期)

2.线程不安全的原因

1.多个变量对一个共享变量做修改

2.线程是抢占式执行的,CPU的调度是随机的

3.原子性:代码没有一次性的执行完毕

4.内存可见性:线程1修改了共享变量的值,线程2不能及时获取到最新的值

5.有序性:由于指令重排序,指令无法按照书写的顺序进行执行.

3.JMM(Java内存模型)

JMM可以解决原子性,内存可见性,有序性的问题

1.主内存,进程启动时在主内存中申请内存资源,也就是内存条,用来保存所有的变量

2.工作内存,对应CPU中的缓存,每个线程都有自己的工作内存,工作内存互不影响,线程之间起到了内存隔离的效果

3.JMM规定,一个线程更新共享变量值的时候,必须先从主内存中加载到变量值到对应线程的工作内存中,修改完成后再将工作内存中的值刷新到主内存中.

4.synchronized锁

1.加锁之后可以将多线程(并发执行)变成单线程(串行执行).   ---解决了原子性

2.由于是单线程执行,线程2读到的值一定是线程1修改过的值  ---解决了内存可见性

3.不能解决有序性

synchronized的使用

1.可以修饰普通的方法  ---锁对象是new出来的对象(当前对象,this)

2.可以修饰静态的方法  ---锁对象是类对象,类名.class

3.可以修饰代码块          ---锁对象是指定的

5.锁对象

1.任何对象都可以充当锁对象,类对象,普通对象

2.锁对象的对象头中的markword区域记录当前争抢到锁的线程信息

3.多线程环境下判断是否发生锁竞争,只需要判断是否争抢的是一把锁.

6.volatile关键字

1.可以解决内存可见性      MESI缓存一致性协议和内存屏障

2.可以解决有序性

3.不能解决原子性

4.只能修饰变量

原子性可见性有序性
synchronizedYYN
volatileNYY

7.wait()和notify()

1.wait()是让线程进入休眠状态,notify()是唤醒等待的线程,都是Object中的类

2.wait()和notify()都会释放锁资源,wait()和notify()要对于同一个锁搭配使用.

 面试题:说一下wait()和sleep()的区别

1.本质上都是让线程等待,但是两个方法没什么关系

2.wait()是Object类中定义的方法,sleep()是Thread类中定义的方法

3.wait()必须与synchronized搭配使用,调用之后会释放锁.sleep()只是让线程进入堵塞等待,和锁没有什么区别

8.Java中线程安全的类

线程安全的类:Vector (不推荐使用)  Stack  HashTable (不推荐使用)  ConcurrentHashMap
StringBuffer

线程不安全的类:ArrayList   LinkedList   HashMap   TreeMap   HashSet   TreeSet   StringBuilder

二.单例模式

1.什么是单例

单例模式是一种设计模式(设计模式:就是在特定的场景下,解决问题最优的方式,类似于棋谱),单例:顾名思义,全局只有一个实例对象

2.怎么设计一个单例

1.口头约定

对外提供一个方法,规定使用者只能通过这个方法来获取这个类的实例对象(不靠谱,有些人就是new出来对象,不采用你这个方法获取对象)

2.使用编程语言的特性

Java中哪些对象时全局唯一的?

.class对象,比如Object.class   类对象

使用static修饰的属性,所有的实例对象访问的都是同一个类属性.

因此我们可以通过类对象和static配合的方式实现单例

实现单例有两种模式,饿汉模式和懒汉模式

三.饿汉模式

类的加载就完成初始化

public class Singleton {private static Singleton instance = new Singleton();private Singleton() {}public static Singleton getInstance() {return instance;}
}

优点:书写简单,不容易出错

四.懒汉模式

1.单线程下的懒汉模式

避免程序启动的时候浪费过多的系统资源,当程序使用这个对象的时候再对这个对象进行初始化

public class SingletonLazy {private static SingletonLazy instance = null;private SingletonLazy() {}public static SingletonLazy getInstance() {//在获取单例对象的时候,判断是否已经被创建,没有创建则创建if (instance == null) {instance = new SingletonLazy();}return instance;}
}

其实也不难写出,只需要在将instance初始化为null,当需要获取实例(getInstance)的时候,判断instance是否为null,为null就创建对象,否则直接返回.

这样我们就实现了懒汉模式的单例吗?当然以上的程序在单线程的情况下是正确的,但是多线程的情况下会出现一些问题.

2.多线程下的懒汉模式

模拟多线程的情况下通过以上程序获取实例对象:

public class Demo02_SingletonLazy {public static void main(String[] args) {//创建是个线程for (int i = 0; i < 10; ++i) {Thread thread = new Thread(() -> {//获取实例对象并打印SingletonLazy instance = SingletonLazy.getInstance();System.out.println(instance);});thread.start();}}
}

打印的结果:

由打印的结果可以看出,发现获取到的对象不一定都是同一个对象,不符合我们的预期,发生了线程不安全的现象

3.分析线程不安全的原因

刚开始的时候instance=null;

 可以观察出来,仅有两个线程的时候,就有可能有两个不同的对象.

其实我们仔细思考可以想出具有不同的对象只会发生没有对象的初期,后期对象不为空的时候,多个线程再进来,对象也不会发生改变了,但我们要求的是单例,所以我们要完全满足单例模式!

为了解决这个问题,我们可以给这个加锁

4.加锁解决这个问题

我们在if循环外面加上锁

public class SingletonLazy {private static SingletonLazy instance = null;private SingletonLazy() {}public static SingletonLazy getInstance() {synchronized (SingletonLazy.class) {//在获取单例对象的时候,判断是否已经被创建,没有创建则创建if (instance == null) {instance = new SingletonLazy();}}return instance;}
}

打印结果:

 我们考虑以下,是否能将synchronized包裹的代码块发到if语句的下面

public class SingletonLazy {private static SingletonLazy instance = null;private SingletonLazy() {}public static SingletonLazy getInstance() {//在获取单例对象的时候,判断是否已经被创建,没有创建则创建if (instance == null) {synchronized (SingletonLazy.class) {instance = new SingletonLazy();}}return instance;}
}

打印的结果:

是不可以的!Load和CMP操作没有原子执行,线程1加载到instace=null,线程2加载到的instace=null,所以线程1和线程2都是new出来一个新的SingletonLazy对象,所以要扩大加锁的范围

进行修改之后看起来就是正确的了,但是不高效.

5.双重检查锁

前面我们已经分析了,线程不安全的线程只存在于前期,也就是instace=null进入到方法的时期,instance!=null的时候是不会发生线程不安全的现象的,但是我们之前写的代码,不论在什么时期都要参与锁竞争,而锁竞争是十分耗费系统资源.

用户态:Java层面,JVM中执行的代码

内核态:执行的是CPU指令,加入synchronized后参与锁竞争就从用户态到内核态,而内核态执行效率没有用户态执行效率高.

来举一个现实中的例子:拿批改作业为例,同学们可以自己批改作业(用户态),也可以上交给老师进行批改(内核态),自己批改效率是很高的,但是交给老师,老师可能要备课,也要批改别人的作业,所以完成你作业的批改是十分不高效的.

public class SingletonLazy {private static SingletonLazy instance = null;private SingletonLazy() {}public static SingletonLazy getInstance() {if (instance == null) {//在获取单例对象的时候,判断是否已经被创建,没有创建则创建synchronized (SingletonLazy.class) {if (instance == null) {instance = new SingletonLazy();}}}return instance;}
}

这种用双重if判断的方式叫做双重检查锁,两层if语句判断的目的不一样,外层if是判断是否为空,避免参与锁竞争,内层if判断是否为空,为instance进行赋值.

初始状态instance=null,外层if判断为true,进入,此时三个线程参与锁竞争,线程1拿到了锁,线程2和线程3处在堵塞状态,线程1内层if判断为true,执行instance的赋值操作,之后释放锁资源,返回赋值之后的对象,线程2拿到了锁资源,内层if判断为false,释放锁资源,返回instance,线程3拿到锁资源后,和线程2一样.

之后instance!=null,外层if判断为false,直接返回instance,不要参与锁竞争,提高了效率.

现在已经做到了确保原子性,内存可见性,但是还没有确保有序性,下面我们做进一步的优化

6.加volatile优化(单例懒汉模式最终版)

给共享变量instance加volatile关键字,可以避免指令重排序问题.

public class SingletonLazy {private static volatile SingletonLazy instance = null;private SingletonLazy() {}public static SingletonLazy getInstance() {if (instance == null) {//在获取单例对象的时候,判断是否已经被创建,没有创建则创建synchronized (SingletonLazy.class) {if (instance == null) {instance = new SingletonLazy();}}}return instance;}
}

懒汉模式的优点:节约资源.

相关文章:

Java之单例模式

目录 一.上节内容 1.什么是线程安全 2.线程不安全的原因 3.JMM(Java内存模型) 4.synchronized锁 5.锁对象 6.volatile关键字 7.wait()和notify() 8.Java中线程安全的类 二.单例模式 1.什么是单例 2.怎么设计一个单例 1.口头约定 2.使用编程语言的特性 三.饿汉模式…...

【分组码系列】线性分组码的网格图和维特比译码

线性分组码的网格图 由于码字的比特位是统计独立的,所以编码过程可以利用有限状态机来描述,它能精确地确定初始和最终状态。可以利用网格图进一步描述编码过程[36],采用维特比算法进行最大似然译码. 在GF(2)上定义线性分组码(n,k)。相应的(n-k)Xn维校验阵可以写成 令码字为系…...

代码命名规范是真优雅呀!代码如诗

日常编码中&#xff0c;代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图&#xff0c;也是一项必备的能力。那它们有什么规律呢&#xff1f; Java项目的代码结构&#xff0c;能够体现它的设计理念。Java采用长命名的方式来规范类的命名&#xff0c;能够自己表达…...

你不知道的自动化?使用自动化测试在项目中创造高业务价值...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 脱离数据支撑谈价…...

通过实现一个简单的 JavaScript 猜数字大小的游戏,介绍如何进行布局样式处理

JavaScript 猜数字大小是一个非常简单、却又经典的游戏&#xff0c;可以锻炼玩家的逻辑思维能力。在这个游戏中&#xff0c;电脑会随机生成一个数字&#xff0c;玩家需要根据提示逐步猜出正确的数字。接下来&#xff0c;我们将通过实现一个简单的 JavaScript 猜数字大小游戏来介…...

Java设计模式(二十二)策略模式

一、概述 策略模式是一种行为型设计模式&#xff0c;它允许在运行时选择算法的行为。策略模式通过将算法封装成独立的策略类&#xff0c;使得它们可以相互替换&#xff0c;而不影响使用算法的客户端。这样可以使客户端代码与具体算法的实现细节解耦&#xff0c;提高了代码的可…...

【沐风老师】一步一步教你在3dMax中进行UVW贴图和展开UVW的方法

将简单或程序材质应用于对象并不难。但是当表面需要在其上显示某种纹理时&#xff0c;它会变得更加复杂。任何纹理贴图都放在材质的 Diffuse 插槽中&#xff0c;但渲染的结果可能无法预测。这就是为什么我们需要了解 3DMAX 如何将纹理应用于 3D 对象&#xff0c;什么是 UVW 贴图…...

Redis主从复制(搭建集群的一种方式)【故障转移,内存,回收】

做一个伪集群 配置文件&#xff1a; daemonize yes port 7777 logfile .redis-7777.log dir ./ bind 0.0.0.0启动6666 and 7777 现在设置主从表 但是有个问题我把服务器停掉 关系就会解除 还可以手动解除 slaveof no one 命令 配置Sentinel&#xff08;哨兵&#…...

专业专注,极致体验,高端隐形智能晾衣机品牌邦先生官宣浙江卫视知名主持人沈涛为品牌代言人

5月11日&#xff0c;高端隐形晾衣架领导品牌邦先生正式宣布&#xff0c;浙江卫视知名主持人沈涛为品牌代言人&#xff0c;以更高标准的晾晒&#xff0c;共同迎接智能晾晒大时代&#xff0c;用科技力量创造美好智慧家居生活。 专业实力品牌邦先生王牌主持沈涛 作为浙江卫视的“王…...

SpringCloud使用SkyWalking实现分布式链路追踪1

文章目录 一、MicrometerTracingBrave(Sleuth)链路追踪1、MicrometerTracingBrave和Zipkin的概论2、Docker搭建Zipkin服务3、MicrometerTracingBrave和Zipkin实现链路追踪 二、SkyWaking服务的安装与使用1、SkyWalking的概论2、Java探针的环境搭建3、Java探针实现日志监控4、Sk…...

【牛客刷题专栏】0x28:JZ30 包含min函数的栈(C语言编程题)

前言 个人推荐在牛客网刷题(点击可以跳转)&#xff0c;它登陆后会保存刷题记录进度&#xff0c;重新登录时写过的题目代码不会丢失。个人刷题练习系列专栏&#xff1a;个人CSDN牛客刷题专栏。 题目来自&#xff1a;牛客/题库 / 在线编程 / 剑指offer&#xff1a; 目录 前言问…...

聚焦丨酷雷曼荣列XRMA联盟成员单位

自“元宇宙”概念兴起之初&#xff0c;酷雷曼VR所属北京同创蓝天云科技有限公司就积极布局、探索和实践。2022年12月&#xff0c;酷雷曼VR成功加入虚拟现实与元宇宙产业联盟&#xff08;XRMA&#xff09;&#xff0c;正式被接纳为联盟成员单位&#xff0c;意味着酷雷曼公司将进…...

物联网架构和技术:如何实现物物互联和智能化控制

第一章&#xff1a;引言 物联网是一种新兴的技术领域&#xff0c;通过将物理设备、传感器和软件等连接起来&#xff0c;可以实现设备之间的互联互通&#xff0c;让各种设备可以进行数据交换和智能化控制。在这个数字化时代&#xff0c;物联网已经成为了连接万物的关键技术之一…...

Linux系统查看CPU信息命令cat /proc/cpuinfo详细说明

Linux操作系统服务器如何查看CPU处理器信息&#xff1f;使用命令cat /proc/cpuinfo可以查看CPU详细信息&#xff0c;包括CPU核数、逻辑CPU、物理CPU个数、CPU是否启用超线程等&#xff0c;阿里云服务器网分享Linux服务器查看CPU信息命令&#xff1a; 目录 Linux服务器查看CPU…...

RK3588旗舰32T人工智能多网口边缘智能网关交换机

32T边缘智能网关发布&#xff0c;助力多行业数字化升级&#xff0c;运维降本增效&#xff0c;搭载RK3588旗舰芯 搭载瑞芯微RK3588芯片的边缘智能网关XM-RK3588&#xff0c;算力可扩展至32T&#xff0c;适用于电力能源、智慧交通、智慧城市、智慧安防、智慧医疗、工业互联网等领…...

一行代码绘制高分SCI火山图

一、概述 在近半年中&#xff0c;我读了很多的高分SCI文章&#xff0c;很多文章中都有多种不同的火山图&#xff0c;包括「普通的火山图、渐变火山图、以及包含GO通路信息的火山图」&#xff01; 经过一段时间的文献阅读和资料查询&#xff0c;终于找到了一个好用而且简单的包…...

chmod是什么?cron是什么?

chmod 和 cron 是 Unix 和类 Unix 系统&#xff08;如 Linux&#xff09;的常用命令。 chmod&#xff1a;这是一个命令行工具&#xff0c;用于更改文件或目录的权限。在 Unix 和类 Unix 系统中&#xff0c;每个文件和目录都有一个访问权限集&#xff0c;该集定义了哪些用户可以…...

励志长篇小说《周兴和》书连载之三 十五岁时做父亲

十五岁时做父亲 周兴和的父亲一天天更衰老了。 他母亲身体也越来越是消瘦。近一两年来&#xff0c;她常常感到全身无力、胸口发堵、心慌气紧、吞咽困难&#xff0c;做什么事都力不从心了。 这时&#xff0c;他母亲不知是心血来潮&#xff0c;还是她预感到了什么&#xff0c;出…...

文件一直处于修改状态 git checkout 无法还原的问题解决方法

问题描述 最近在 RT-Thread 时&#xff0c;使用 Git 回退版本验证问题&#xff0c;后来 git pull 拉取最新代码后&#xff0c;发现里面有几个文件&#xff0c;一直为【修改】状态&#xff0c;并且无法还原&#xff0c;git checkout xxx git reset --hard 都用了&#xff0c;依旧…...

Julia入门-3、Julia包管理工具

文章目录 0、Julia 的包管理工具是Pkg1、使用Julia包管理工具过慢 0、Julia 的包管理工具是Pkg Julia 的包管理工具是Pkg&#xff0c;可以用于安装、更新、卸载和管理 Julia 中的软件包。以下是一些常用的 Pkg命令&#xff1a; Pkg.add("Package")&#xff1a;安装一…...

选择正确的 Azure 存储服务

Azure Storage 是 Microsoft 基于云的存储解决方案&#xff0c;提供了全面的现代存储服务。在本文中&#xff0c;我们将探讨各种可用的服务及其特定用例&#xff0c;使您能够选择最适合您需求的服务。 Azure Blob 存储 Azure Blob 存储是一项功能强大且可缩放的存储服务&…...

隐语团队研究成果再创佳绩,两篇论文分别被USENIX ATC‘23和IJCAI‘23接收!

‍“USENIX ATC‍年度技术会议”&#xff08;USENIX ATC&#xff0c;USENIX Annual Technical Conference&#xff09;是计算机系统领域的顶级学术会议之一。本年度 USENIX ATC’23将于7月10日至12日在美国波士顿召开。本次会议共投稿353篇论文&#xff0c;接收65篇&#xff0c…...

美团数据指标体系搭建实战

在美团商家版中&#xff0c;美团为商家搭建的数据指标体系&#xff0c;很好的指导了商家的经营发展方向以及提供经营状况概览。​ 本文通过体验美团商家版经营数据子功能&#xff0c;对美团商家版数据指标体系搭建的情况做出一个概述。 美团商家版的店铺子功能下&#xff0c;…...

prometheus实战之五:飞书通知告警

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 《prometheus实战》系列链接 prometheus实战之一&#xff1a;用ansible部署prometheus实战之二&#xff1a;使用常见指标prometheus实战之三&#xff1a;告警…...

【华为OD机试真题】不含101的数(python版)100%通过率 超详细代码注释 代码解读

【华为OD机试真题 2022&2023】真题目录 @点这里@ 【华为OD机试真题】信号发射和接收 &试读& @点这里@ 【华为OD机试真题】租车骑绿道 &试读& @点这里@ 不含101的数 时间限制:1s空间限制:256MB限定语言:不限 题目描述: 小明在学习二进制时,发现了一…...

基于AT89C52单片机的交通信号灯设计

点击链接获取Keil源码与Project Backups仿真图&#xff1a; https://download.csdn.net/download/qq_64505944/87772657 源码获取 主要内容&#xff1a; 本次设计所提出的一种基于单片机技术的简易计算器的方案&#xff0c;能更好的解决计算机计算的问题,随着数字生活的到来&…...

chatGPT4.0-基于Python+Appium的APPUI关键字驱动自动化测试框架demo

以下是一个简单的UI关键字驱动+数据驱动的自动化测试框架代码示例,使用Python和Appium进行移动应用测试。我们将使用openpyxl库读取Excel数据,使用Appium-Python-Client库进行UI自动化测试。 首先,请确保已安装以下库: pip install openpyxl pip install Appium-Python-C…...

C++模板进阶

一、非类型模板参数 模板参数分为&#xff1a;类型形参、非类型形参 类型形参&#xff1a;class与typename都是参数类型 非类型形参&#xff1a;用一个常量作为模板的一个参数&#xff0c;一般是整型常量 #include<iostream> #include<array> using namespace …...

【人力资源管理】第4集 免费开源ERP: Odoo 16 Appraisal员工绩效评估 构建一体化企业人力资源管理

文章目录 前言一、概览二、主要功能1.设置定期的员工评估2.构建正确的评估3.设计您自己的调查4.自动评估过程 总结 前言 在员工工作中创建评估。同时审查员工表现。 一、概览 员工评价 评估内容 目标制定 评价指标 评价分析 二、主要功能 1.设置定期的员工评估 强化贵公司的…...

「AI 孙燕姿」翻唱华语乐坛歌曲爆红全网,AI 翻唱将带来哪些影响?是否会有版权等问题?

在某视频平台上&#xff0c;“AI孙燕姿”成了新网红&#xff0c;它翻唱过周杰伦的《发如雪》、翻唱过郭顶的《水星记》、翻唱过赵雷的《我记得》&#xff0c;受到了网友的追捧&#xff0c;甚至有网友宣布“这是2023年最火的声音”。 网上除了AI孙燕姿&#xff0c;还有AI周杰伦…...