设计模式之单列模式
单列模式是一种经典的设计模式,在校招中最乐意考的设计模式之一~
设计模式就是软件开发中的棋谱,大佬们针对一些常见的场景,总结出来的代码的编写套路,按照套路来写,不说你写的多好,至少不会太差~
在校招中,主要考察两个设计模式:单列模式,工厂模式
本文主要讲解单列模式
单列《——》单列模式(instance)对象
一个程序中,某个类只创建出一个实列(对象)——》不能创建多个对象!
Java中的单列模式借助Java语法,保证某个类只能创建出一个实列,而不能new多次!!有些场景,本身就是要求某个概念是单列的!!
在Java语法中,如何做出单列模式的实现呢??
Java中实现单列模式的有很多种写法:起码有5/6种写法,但是课堂上主要说两种:
- 饿汉模式(饥饿)
- 懒汉模式(从容)
饿汉:吃完饭就立刻去洗碗
懒汉:吃完饭之后,先把碗放到一边,等到下一顿吃的时候,需要用到碗了再洗,通常认为懒汉模式更好(效率更高)
比如:中午吃饭,用了4个碗
饿汉:吃完就得把4个碗都洗了
懒汉:晚上吃饭只用2个碗,此时只需要洗2个就ok了
计算机中的列子,打开一个硬盘上的文件,读取文件内容,并显示出来:
饿汉:把文件所有的内存都读到内存中,并显示出来
懒汉:只把文件读一小部分,把当前屏幕填充上,如果用户翻页了,在读其他文件内容,如果不翻页就省下了
假设文件非常大:10G:
饿汉模式:文件可能卡半天!内存够不够??
懒汉模式:可以快速打开!
我们来看一下下述代码吧:饿汉模式:
class Singleton{//唯一的实体private static Singleton instance=new Singleton();//获取到实列的方法public static Singleton getInstance(){return instance;//单词的读操作,不涉及修改}//禁止外部new实列//此处,在类内部把实列创建好,同时禁止外部重新创建实列,此时就可以保证是单列的特性了!private Singleton(){//构造方法设为private//仅类内部使用}
}public class Main {public static void main(String[] args) {//此时s1和s2是同一个对象Singleton s1=Singleton.getInstance();Singleton s2=Singleton.getInstance();//Singleton s3=new Singleton();//此处要把new操作禁止掉,则把该类的构造方法设为private即可}
}
上述代码是线程安全的(饿汉模式),先创建好实列,随去随用~
private static Singleton instance=new Singleton();
在上述的该段代码中:被static修饰,该属性是类的熟悉,JVM中,每个类的类对象只有唯一一份,类对象里的这个成员,自然也是唯一的!!
但是对于创建的这个实列,我们可以用不到,因此:非必要不创建《——》懒汉模式
懒汉模式的核心思想:——》非必要不创建
//通过懒汉模式实现一下单列模式
class SingletonLazy{volatile private static SingletonLazy instance=null;//先置为空//只有调用getInstance才会new一个对象,如果再次调用getInstance,仍然会返回之前的实列public static SingletonLazy getInstance(){//这个条件,判定是否需要加锁,如果对象已经有了,//就不必加锁了,此时本身就是线程安全的if (instance==null){synchronized (SingletonLazy.class){//加锁,保证判定和new是一个原子操作if (instance==null){instance=new SingletonLazy();}}}return instance;//唯一}private SingletonLazy(){//构造方法设为private//类中可以访问,类外不能访问}
}public class Main1 {public static void main(String[] args) {SingletonLazy s1=SingletonLazy.getInstance();SingletonLazy s2=SingletonLazy.getInstance();//此时s1和s2是同一个实列System.out.println(s1==s2);//true}
}
显而易见,上述代码的运行结果为:
思考一下:对于前面的饿汉模式和懒汉模式的两个代码,是否线程安全??
对于饿汉模式:认为线程安全的——》只是读数据
对于懒汉模式:多线程下调用getInstance,可能会出现问题《——》线程不安全
多线程下,懒汉模式可能无法保证创建对象的唯一性!!
懒汉模式的部分代码如下:
如果是N个线程一起调用,可能就会搞出N个对象了!!
通过加锁操作《——》锁要加在哪里??多线程的代码是很复杂的,不是说只要写了加锁操作,就一定是线程安全了,只能具体问题具体分析。
加锁,是一个比较低效的操作(加锁就可能涉及到阻塞等待~)!!非必要不加锁
对于getInstance()这个方法:
在该段代码中,任何时候调用getInstance(),都会触发锁的竞争。
其实,此处的线程不安全,只出现在首次创建对象这里,一旦对象new好了,后续在调用getInstance(),就只是单纯的读操作了,就没有线程安全问题,就没有必要再加锁了!!
因此,可以在加一个if语句的判定(两个if语句的判定更加完美)
这两个if (instance==null)的代码,看起来一样,实际上,他俩的差别很大!!按照咱们之前的理解,两行代码如果紧挨着的,此时两行代码就会被迅速的执行完,近似就可以看作是“同一时机”,实际上,由于这两个if中间间隔了个synchronized,加锁可能导致阻塞,至于啥时候解除阻塞,时间不一定!!虽然两个条件相同,但是如果调用时间长了,结果也可能会不同~!!
加上volatile可以解决指令重排序的问题:
volatile private static SingletonLazy instance=null;//先置为空
小结一下,瞬间开心:
单列模式的线程安全问题:(经典面试题)
饿汉模式:天然就是安全的,只是读操作
懒汉模式:不安全,有读也有写操作
- 加锁,把if和new变成原子操作
- 双重if,减少不必要的加锁操作
- 使用volatile,禁止指令重排序,保证后续线程拿到的是完整对象
相关文章:

设计模式之单列模式
单列模式是一种经典的设计模式,在校招中最乐意考的设计模式之一~ 设计模式就是软件开发中的棋谱,大佬们针对一些常见的场景,总结出来的代码的编写套路,按照套路来写,不说你写的多好,至少不会太差~ 在校招中…...

linux内核模块编译方法详解
文章目录 前言一、静态加载法1.1 编写驱动程序1.2 将新功能配置在内核中1.3为新功能代码改写Makefile1.4 make menuconfig界面里将新功能对应的那项选择为<*> 二、动态加载法2.1 新功能源码与Linux内核源码在同一目录结构下2.2 新功能源码与Linux内核源码不在同一目录结构…...
简介shell的关联数组与普通数组
本文首先介绍shell的关联数组,然后介绍shell的普通数组,最后总结它们的共同语法。 shell的关联数组 定义一个关联数组,并打印它的key-value对 #!/bin/sh# 声明一个关联数组 declare -A HASH_MAP# 给关联数组赋值 HASH_MAP["Tom"…...
玩转Mysql系列 - 第17篇:存储过程自定义函数详解
这是Mysql系列第17篇。 环境:mysql5.7.25,cmd命令中进行演示。 代码中被[]包含的表示可选,|符号分开的表示可选其一。 需求背景介绍 线上程序有时候出现问题导致数据错误的时候,如果比较紧急,我们可以写一个存储来…...
自动驾驶:轨迹预测综述
自动驾驶:轨迹预测综述 轨迹预测的定义轨迹预测的分类基于物理的方法(Physics-based)基于机器学习的方法(Classic Machine Learning-based)基于深度学习的方法(Deep Learning-based)基于强化学习…...

【uniapp/uview】u-datetime-picker 选择器的过滤器用法
引入:要求日期选择的下拉框在分钟显示时,只显示 0 和 30 分钟; <u-datetime-picker :show"dateShow" :filter"timeFilter" confirm"selDateConfirm" cancel"dateCancel" v-model"value1&qu…...

如何使用Docker部署Nacos服务?Nacos Docker 快速部署指南: 一站式部署与配置教程
🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…...

yocto stm32mp1集成ros
yocto stm32mp1集成ros yocto集成ros下载meta-rosyocto集成rosrootfs验证 yocto集成ros 本章节介绍yocto如何集成ros系统用来作机器人开发。 下载meta-ros 第一步首先需要下载meta-ros layer,meta-ros的链接如下:https://github.com/ros/meta-ros/tre…...

Linux 中的 chroot 命令及示例
Linux/Unix系统中的chroot命令用于更改根目录。Linux/Unix 类系统中的每个进程/命令都有一个称为root 目录的当前工作目录。它更改当前正在运行的进程及其子进程的根目录。 在此类修改的环境中运行的进程/命令无法访问根目录之外的文件。这种修改后的环境称为“ chroot监狱”或…...
oracle的redo与postgreSQL的WAL以及MySQL的binlog区别
Oracle的redo日志、PostgreSQL的WAL(Write-Ahead Log)以及MySQL的binlog(二进制日志)都是数据库的事务日志,但它们在实现和功能上有一些区别。 1. 实现方式: - Oracle的redo日志是通过在事务提交前将事务操作记录到磁盘上的重做日志文件中来实现的。 - PostgreSQL…...

进入低功耗和唤醒
休眠模式 进入休眠模式 如果使用 WFI 指令进入睡眠模式,则嵌套向量中断控制器 (NVIC) 确认的任意外设中断都会 将器件从睡眠模式唤醒。 如果使用 WFE 指令进入睡眠模式,MCU 将在有事件发生时立即退出睡眠模式。唤醒事件可 通过以下方式产生ÿ…...

【多线程】volatile 关键字
volatile 关键字 1. 保证内存可见性2. 禁止指令重排序3. 不保证原子性 1. 保证内存可见性 内存可见性问题: 一个线程针对一个变量进行读取操作,另一个线程针对这个变量进行修改操作, 此时读到的值,不一定是修改后的值,即这个读线…...
【Windows注册表内容详解】
Windows注册表内容详解 第一章节 注册表基础 一、什么是注册表 注册表是windows操作系统、硬件设备以及客户应用程序得以正常运行和保存设置的核心“数据库”,也可以说是一个非常巨大的树状分层结构的数据库系统。 注册表记录了用户安装在计算机上的软件和每个程…...

大数据Hadoop入门之集群的搭建
hadoop的三种运行模式 本地模式:测试本地的hadoop是否能够运行,用来运行官方的代码。伪分布模式:原先有人拿来测试,目前测试都不用这个模式了。完全分布模式:多台服务器组成分布式环境,生产环境使用 分布式主机文件同步命令 sc…...

华为云云耀云服务器L实例评测|基于云服务器的minio部署手册
华为云云耀云服务器L实例评测|基于云服务器的minio部署手册 【软件安装版本】【集群安装(是)(否)】 版本 创建人 修改人 创建时间 备注 1.0 jz jz 2023.9.2 minio华为云耀服务器 一. 部署规划与架…...

龙智携手Atlassian和JFrog举办线下研讨会,探讨如何提升企业级开发效率与质量
2023年9月8日,龙智将携手Atlassian和JFrog于上海举办线下研讨会,以“大规模开发创新:如何提升企业级开发效率与质量”为主题,邀请龙智高级咨询顾问、Atlassian认证专家叶燕秀,紫龙游戏上海研发中心高级项目管理主管叶凯…...

2023数学建模国赛A题定日镜场的优化设计- 全新思路及代码
背景资料关键信息和要点如下: 定日镜:塔式太阳能光热发电站的基本组件,由纵向转轴和水平转轴组成,用于反射太阳光。 定日镜场:由大量的定日镜组成的阵列。 集热器:位于吸收塔顶端,用于收集太…...

CSS笔记(黑马程序员pink老师前端)圆角边框
圆角边框 border-radius:length; 效果显示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Documen…...

水表电表集中远程抄表系统分析
电表水表远程抄表系统石家庄光大远通电气有限公司主要经营自动抄表,远程抄表,集中抄表,新供应信息,是石家庄光大远通电气有限公司自动远程抄表系统集信号采集、网络通信于一体的高性能抄表装置,该系统以485通讯方式读取水表电表的数据,以MBUS通讯方式读取…...
Android 通知
1. 原生Android通知的几种显示方式: 状态栏的图标:发出通知后,通知会先以图标的形式显示在状态栏中。 抽屉式通知栏:用户可以在状态栏向下滑动以打开抽屉式通知栏,并在其中查看更多详情及对通知执行操作。在应用或用户…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...