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

Java Web 实战 07 - 多线程基础之单例模式

大家好 , 这篇文章给大家带来的是单例模式 , 单例模式中分为懒汉模式和饿汉模式 , 懒汉模式是需要用的到的时候才去创建实例 , 而饿汉模式是程序一启动就立刻创建实例 , 在这其中还有很多其他问题需要我们去研究
推荐大家跳转到这里 , 观看效果更加
上一篇文章的链接我也贴在这里了
在这里插入图片描述

单例模式

  • 单例模式
  • 1. 饿汉模式 : 程序启动立即创建实例
  • 2. 懒汉模式 : 程序启动先不创建实例 , 等到真正有用的时候再创建实例
  • 3. 正题 : 上述的两个单例模式的代码在多线程环境下调用 getInstance() 是线程安全的吗?

单例模式

单例模式是一种非常常见的设计模式

设计模式就相当于棋谱 , 前人总结出的一些固定套路 , 如果我们按照这些固定套路 , 代码就不会写的太离谱

设计模式虽然很有用 , 但是需要大家有一定的编程经验才好理解一点
未来肯定会经常和设计模式打交道 , 但是现在我们还是学习一下面试中比较常见的设计模式
校招中 , 关于设计模式 , 主要考察两个 : 单例模式、工厂模式

单例模式的目的就是 : 有些对象 , 在一个程序中应该只有一个实例 , 就可以使用单例模式
在单例模式下 , 对象的实例化就被限制了 , 只能创建一个 , 多的就不能再创建了

单例模式就是借助相关语法强制限制咱们不能创建多个实例

开车为啥要系安全带 ?
大家都不想出现事故 , 但是通过司机并不能完全保证安全
所以就出现了安全带 , 一定程度上保证了安全

在 Java 中 , 单例模式有很多种实现方式
我们主要介绍两个 : 饿汉模式 和 懒汉模式
他们俩描述的是 创建实例的时机
饿汉模式 : 程序启动立即创建实例
懒汉模式 : 程序启动先不创建实例 , 等到真正有用的时候再创建实例

大家不要把懒理解成贬义词 , 在计算机中 , 懒这个字往往意味着性能比较高
许多科技的发明都是因为人类懒 , 想要方便生活

计算机中 , 这种思想很常见
硬盘里面有许多大文件
使用文件资源管理器打开它

  1. 饿汉模式 : 把这些大文件通通读到内存中 , 读取完毕之后再让用户进行查看和修改
  2. 懒汉模式 : 只读取出当前页面能显示出的范围的文件数目 , 随着用户翻页 , 继续再读后面内容 , 用户还没翻到 , 就不着急度

或者刷抖音 , 不是一下子加载出所有的视频 , 而是一个一个加载 , 刷完了再加载下一条
或者微信朋友圈 , 只有当你点进去的时候 , 才会加载原图 , 否则就不加载

1. 饿汉模式 : 程序启动立即创建实例

// 单例模式的实现
// 饿汉模式
class Singleton {// 创建实例,把创建的实例赋值给一个静态变量// 静态变量又叫做类变量,类对象在整个程序中只有唯一一个实例->保证了单例private static Singleton instance = new Singleton();// 通过这个静态方法返回独苗实例// 后续如果需要使用这个实例,统一基于getInstance方法来获取咱们的独苗实例,就不需要去new了public static Singleton getInstance() {return instance;}// 构造方法设为私有:其他的类想来new就不行了// 从根本上禁止了其他代码来new Singleton 实例了private Singleton() {}
}public class Demo19 {public static void main(String[] args) {Singleton instance1 = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();// 创建的是同一个实例System.out.println(instance1 == instance2);// true}
}

如果我们再手动创建一个实例 , 就会报错
image.png

单例模式的关键是 : 使用静态成员表示实例 (唯一性) + 让构造方法为私有 (堵住了 new 创建新实例的方式)

那么这段代码为什么说是饿汉模式呢 ?
image.png

2. 懒汉模式 : 程序启动先不创建实例 , 等到真正有用的时候再创建实例

// 单例模式的实现
// 懒汉模式
class SingletonLazy {// 先不着急实例化private static SingletonLazy instance = null;public static SingletonLazy getInstance() {// 进行判断// 为空->创建实例if(instance == null) {instance = new SingletonLazy();}return instance;}// 构造方法同样也是 private 的private SingletonLazy() {}
}public class Demo19 {public static void main(String[] args) {Singleton instance1 = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();}
}

image.png

3. 正题 : 上述的两个单例模式的代码在多线程环境下调用 getInstance() 是线程安全的吗?

饿汉模式是天然线程安全的
image.png
懒汉模式是线程不安全的
image.png
懒汉模式一旦实例创建好之后 , 后续 if 条件就进不去了 , 此时也就全是读操作了 , 也就线程安全了
所以我们要是想让懒汉模式变成线程安全的 , 就一定要解决第一次创建实例的过程

那如何解决懒汉模式的线程不安全问题呢 ?
解决办法就是加锁

// 单例模式的实现
// 懒汉模式
class SingletonLazy {// 先不着急实例化private static SingletonLazy instance = null;public static SingletonLazy getInstance() {// 进行判断// 为空->创建实例synchronized (SingletonLazy.class) {if(instance == null) {instance = new SingletonLazy();}}return instance;}// 构造方法同样也是 private 的private SingletonLazy() {}
}public class Demo19 {public static void main(String[] args) {Singleton instance1 = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();}
}

image.png
但是目前还是有问题
懒汉模式只是初始情况下 , 才会有线程不安全问题
一旦实例创建好了之后 , 此时就安全了
既然如此 , 后续再调用 getInstance 的时候就不应该再去加锁了
当线程已经安全了 , 我们再尝试进行加锁 , 其实就非常影响效率了
所以我们需要做到 : 该加锁的地方需要加锁 , 不该加锁的时候别乱加锁
我们只需要再加上一层 if 判定就 ok 了

// 单例模式的实现// 懒汉模式
class SingletonLazy {// 先不着急实例化private static SingletonLazy instance = null;public static SingletonLazy getInstance() {// 进行判断// 为空->创建实例if(instance == null) {synchronized (SingletonLazy.class) {if(instance == null) {instance = new SingletonLazy();}}}return instance;}// 构造方法同样也是 private 的private SingletonLazy() {}
}public class Demo19 {public static void main(String[] args) {Singleton instance1 = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();}
}

image.png
image.png

外层 if 为了降低加锁的频率 , 降低锁冲突的概率 . 里层 if 才是真正判定是否要实例化
我们再举个栗子帮大家理清楚为什么要用双层判断
image.png
其中 , 一个线程读 , 一个线程写还存在内存可见性问题
image.png

// 单例模式的实现
// 懒汉模式
class SingletonLazy {// 先不着急实例化volatile private static SingletonLazy instance = null;public static SingletonLazy getInstance() {// 进行判断// 为空->创建实例if(instance == null) {synchronized (SingletonLazy.class) {if(instance == null) {instance = new SingletonLazy();}}}return instance;}// 构造方法同样也是 private 的private SingletonLazy() {}
}public class Demo19 {public static void main(String[] args) {Singleton instance1 = Singleton.getInstance();Singleton instance2 = Singleton.getInstance();}
}

image.png

对于 volatile , 有一种大家认同比较多的说法是这样
volatile 在此处的用途 , 是禁止指令重排序
image.png


关于这里 , 还有可能问到对象存储在哪里的问题 , 我们也需要格外关注一下
image.png

单例模式的分析就到这里了 , 觉得有收获的请一键三连嗷~
在这里插入图片描述

相关文章:

Java Web 实战 07 - 多线程基础之单例模式

大家好 , 这篇文章给大家带来的是单例模式 , 单例模式中分为懒汉模式和饿汉模式 , 懒汉模式是需要用的到的时候才去创建实例 , 而饿汉模式是程序一启动就立刻创建实例 , 在这其中还有很多其他问题需要我们去研究 推荐大家跳转到这里 , 观看效果更加 上一篇文章的链接我也贴在这…...

uniapp上实现左右关联滚动

先看效果&#xff1a; 代码&#xff1a; <template><view class"container"><!-- 左侧fixed导航区域 --><view class"left"><viewv-for"item in leftList":key"item.id"class"left_item":class…...

Docker Remote API未授权访问

目录Docker简述Docker 2375端口安全风险Docker命令连接利用声明&#xff1a;本文仅供学习参考&#xff0c;其中涉及的一切资源均来源于网络&#xff0c;请勿用于任何非法行为&#xff0c;否则您将自行承担相应后果&#xff0c;本人不承担任何法律及连带责任。Docker简述 Docke…...

【蓝桥杯】第十四届蓝桥杯模拟赛(第三期)C++ (弱go的记录,有问题的话求指点)

博主是菜鸡啦&#xff0c;代码仅供参考&#xff0c;只确定能过样例&#xff0c;嘻嘻~第一题&#xff0c;填空题问题描述请找到一个大于 2022 的最小数&#xff0c;这个数转换成十六进制之后&#xff0c;所有的数位&#xff08;不含前导 0&#xff09;都为字母&#xff08;A 到 …...

算法24:LeetCode_并查集相关算法

目录 题目一&#xff1a;力扣547题&#xff0c;求省份数量 题目二&#xff1a;岛屿数量 题目三&#xff1a;岛屿数量拓展 什么是并查集&#xff0c;举个简单的例子。学生考试通常会以60分为及格分数&#xff0c;我们将60分及以上的人归类为及格学生&#xff0c;而60分以下归…...

TypeScript核心知识点

TypeScript 核心 类型注解 知道&#xff1a;TypeScript 类型注解 示例代码&#xff1a; // 约定变量 age 的类型为 number 类型 let age: number 18 age 19: number 就是类型注解&#xff0c;它为变量提供类型约束。约定了什么类型&#xff0c;就只能给该变量赋值什么类型的…...

基于“遥感+”融合技术在碳储量、碳收支、碳循环等多领域监测与模拟实践

以全球变暖为主要特征的气候变化已成为全球性环境问题&#xff0c;对全球可持续发展带来严峻挑战。2015年多国在《巴黎协定》上明确提出缔约方应尽快实现碳达峰和碳中和目标。2019年第49届 IPCC全会明确增加了基于卫星遥感的排放清单校验方法。随着碳中和目标以及全球碳盘点的现…...

外卖点餐系统小程序 PHP+UniAPP

一、介绍 本项目是给某大学餐厅开发的外面点餐系统&#xff0c;该项目针对校内的学生&#xff0c;配送由学校的学生负责配送。因此&#xff0c;该项目不同于互联网的外卖点餐系统。 该系统支持属于 Saas 系统&#xff0c;由平台端、商家端、用户端、以及配送端组成。 其中&a…...

vuex3的介绍与state、actions和mutations的使用

一、定义官网&#xff1a;Vuex 是什么&#xff1f; | Vuex (vuejs.org)Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。二、安装cdn<script src"/path/…...

windows 自带端口转发

使用Portproxy模式下的Netsh命令即能实现Windows系统中的端口转发&#xff0c;转发命令如下: netsh interface portproxy add v4tov4 listenaddress[localaddress] listenport[localport] connectaddress[destaddress]listenaddress – 等待连接的本地ip地址 listenport – 本…...

【算法】算法基础入门详解:轻松理解和运用基础算法

&#x1f600;大家好&#xff0c;我是白晨&#xff0c;一个不是很能熬夜&#x1f62b;&#xff0c;但是也想日更的人✈。如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下&#x1f440;白晨吧&#xff01;你的支持就是我最大的动力&#xff01;&#x1f4…...

2.9.1 Packet Tracer - Basic Switch and End Device Configuration(作业)

Packet Tracer - 交换机和终端设备的基本 配置地址分配表目标使用命令行界面 (CLI)&#xff0c;在两台思科互联网络 操作系统 (IOS) 交换机上配置主机名和 IP 地址。使用思科 IOS 命令指定或限制对设备 配置的访问。使用 IOS 命令来保存当前的运行配置。配置两台主机设备的 IP …...

AtCoder Beginner Contest 216(F)

F - Max Sum Counting 链接&#xff1a; F - Max Sum Counting 题意 两个 大小为 nnn 的序列 aiaiai 和 bibibi&#xff0c;任意选取一些下标 iii&#xff0c;求 max⁡(ai)>∑bi\max(ai) > \sum{bi}max(ai)>∑bi的方案数。 解析 首先考虑状态 一是和&#xff0c;…...

每天学一点之Stream流相关操作

StreamAPI 一、Stream特点 Stream是数据渠道&#xff0c;用于操作数据源&#xff08;集合、数组等&#xff09;所生成的元素序列。“集合讲的是数据&#xff0c;负责存储数据&#xff0c;Stream流讲的是计算&#xff0c;负责处理数据&#xff01;” 注意&#xff1a; ①Str…...

MatCap模拟光照效果实现

大家好&#xff0c;我是阿赵 之前介绍过各种光照模型的实现方法。那些光照模型的实现虽然有算法上的不同&#xff0c;但基本上都是灯光方向和法线方向的计算得出的明暗结果。 下面介绍一种叫做MatCap的模拟光照效果&#xff0c;这种方式计算非常简单&#xff0c;脱离灯光的计算…...

二十一、PG管理

一、 PG异常状态说明 1、 PG状态介绍 可以通过ceph pg stat命令查看PG当前状态&#xff0c;健康状态为“active clean” [rootrbd01 ~]# ceph pg stat 192 pgs: 192 activeclean; 1.3 KiB data, 64 MiB used, 114 GiB / 120 GiB avail; 85 B/s rd, 0 op/s2、pg常见状态 状…...

SAPUI5开发01_01-Installing Eclipse

1.0 简要要求概述: 本节您将安装SAPUI 5,以及如何在Eclipse Juno中集成SAPUI 5工具。 1.1 安装JDK JDK 是一种用于构建在 Java 平台上发布的应用程序、Applet 和组件的开发环境,即编写 Java 程序必须使用 JDK,它提供了编译和运行 Java 程序的环境。 在安装 JDK 之前,首…...

Qt之高仿QQ系统设置界面

QQ或360安全卫士的设置界面都是非常有特点的,所有的配置项都在一个垂直的ScrollArea中,但是又能通过左侧的导航栏点击定位。这样做的好处是既方便查看指定配置项,又方便查看所有配置项。 一.效果 下面左边是当前最新版QQ的系统设置界面,右边是我的高仿版本,几乎一毛一样…...

JVM概览:内存空间与数据存储

核心的五个部分虚拟机栈&#xff1a;局部变量中基础类型数据、对象的引用存储的位置&#xff0c;线程独立的。堆&#xff1a;大量运行时对象都在这个区域存储&#xff0c;线程共享的。方法区&#xff1a;存储运行时代码、类变量、常量池、构造器等信息&#xff0c;线程共享。程…...

固态存储设备固件升级方案

1. 前言 随着数字化时代的发展&#xff0c;数字数据的量越来越大&#xff0c;相应的数据存储的需求也越来越大&#xff0c;存储设备产业也是蓬勃发展。存储设备产业中&#xff0c;发展最为迅猛的则是固态存储(Solid State Storage&#xff0c;SSS)。数字化时代&#xff0c;海量…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...