【JavaEE】多线程(4) -- 单例模式

目录

什么是设计模式?

1.饿汉模式

2.懒汉模式

线程安全问题


什么是设计模式?

设计模式好⽐象棋中的 "棋谱". 红⽅当头炮, ⿊⽅⻢来跳. 针对红⽅的⼀些⾛法, ⿊⽅应招的时候有⼀ 些固定的套路. 按照套路来⾛局势就不会吃亏.

软件开发中也有很多常⻅的 "问题场景". 针对这些问题场景, ⼤佬们总结出了⼀些固定的套路. 按照这 个套路来实现代码, 也不会吃亏.

单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建出多个实例. 这⼀点在很多场景上都需要. ⽐如 JDBC 中的 DataSource 实例就只需要⼀个. 

单例模式具体的实现⽅式有很多. 最常⻅的是 "饿汉" 和 "懒汉" 两种.

1.饿汉模式

所谓 "饿" 形容 "非常迫切" , 实例实在类加载的时候就创建了, 创建时机非常早, 相当于程序一启动 , 实例就创建了, 就使用 "饿汉" 形容创建实例非常早. 

class Singleton {private static Singleton instance = new Singleton();public static Singleton getInstance() {return instance;}private Singleton(){}; //阻止后续代码new出新的实例
}

2.懒汉模式

类加载的时候不创建实例. 第⼀次使⽤的时候才创建实例.

// 懒汉模式实现单例模式
class SingletonLazy {// 这个引用指向唯一的实例, 先初始化为null, 而不是立即创建实例private static SingletonLazy instance = null;public SingletonLazy getInstance() {if(instance == null) {instance = new SingletonLazy();}return instance;}private SingletonLazy() {};
}

如果是首次调用 getInstance , 那么此时 instance 引用为 null, 就会进入 if 条件, 从而把实例创建出来. 如果是后续再次调用 getInstance , 由于instance 已经不再是 null, 此时不会进入 if , 直接返回之前创建好的引用了. 

这样设定, 既可以保证该类的实例是唯一一个, 于此同时, 创建实例的实际就不是程序驱动时了, 而是第一次调用 getInstance 的时候. 

线程安全问题

对于饿汉模式来说, getInstance 方法直接返回 Instance 实例, 这个操作本质就是"读操作", 多个线程读取同一个变量, 是线程安全的.

在懒汉模式中, 如下图所示,

有可能会创建出多个实例, 是线程不安全的.

下面是一个改进的代码: 

class SingletonLazy {private static SingletonLazy instance = null;private static Object locker = new Object();public static SingletonLazy getInstance() {synchronized (locker) {if(instance == null) {instance = new SingletonLazy();}return instance;}}private SingletonLazy(){ };
}

这个代码虽然解决的线程不安全的问题, 但是每次执行这串代码的时候都要进行加锁解锁的操作, 这样程序的效率就变差了, 如果在加锁前先进行判断是否需要加锁, 就可以提高程序的效率了.

再次改进后的代码:

class SingletonLazy {private static SingletonLazy instance = null;private static Object locker = new Object();public static SingletonLazy getInstance() {if(instance == null) {//如果 instance 为 null, 就说明是首次调用, 首次调用就要考虑线程安全问题, 就要加锁//如果是非 null, 就说明是后续调用, 就不用加锁了synchronized (locker) {if(instance == null) {instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){ };
}

然而, 这段代码还有进一步改进的空间!

解决上述问题核心方法是使用 volatile 关键字

volatile 关键字有两个功能:

  1. 保证内存可见性, 每次访问变量必须要重新读取内存, 而不会优化到寄存器/缓存中
  2. 禁止使用指令重排序. 针对被 volatile 修饰的变量的读写操作相关指令, 是不能被重排序的.

最终修改后的代码: 

class SingletonLazy {public volatile SingletonLazy instance = null;Object locker = new Object();public SingletonLazy getInstance() {if(instance == null) {synchronized (locker) {if(instance == null) {instance = new SingletonLazy();}}}return instance;}private SingletonLazy(){}
}

 

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

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

相关文章

Mybatis中的${}和#{}区别

前言 动态 sql 是 mybatis 的主要特性之一,在 mapper 中定义的参数传到 xml 中之后,在查询之前, mybatis 会对其进行动态解析。mybatis 为我们提供了两种支持动态 sql 的语法:#{}以及${} 提示:以下是本篇文章正文内容…

【c++】string的模拟实现

目录 一. 交换函数swap 二. 默认成员函数 构造函数和析构函数 拷贝构造函数和赋值运算符重载 三. 容量相关操作接口 size 与 capacity reserve 与 resize 附:reserve与resize的区别 四. 修改相关操作接口 push_pack append insert 与 erase operato…

软件设计师——数据结构(一)

📑前言 本文主要是【数据结构】——软件设计师——数据结构的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是听风与他🥇 ☁️博客首页:CSDN主页听风与他 &#x1f304…

Flink系列之:窗口Top-N

Flink系列之:窗口Top-N 一、窗口Top-N二、示例:在窗口聚合后进行窗口 Top-N三、在窗口表值函数后进行窗口 Top-N四、限制 一、窗口Top-N 适用于流、批一体窗口 Top-N 是特殊的 Top-N,它返回每个分区键的每个窗口的N个最小或最大值。与普通To…

时序分解 | Matlab实现DBO-VMD基于蜣螂优化算法优化VMD变分模态分解时间序列信号分解

时序分解 | Matlab实现DBO-VMD基于蜣螂优化算法优化VMD变分模态分解时间序列信号分解 目录 时序分解 | Matlab实现DBO-VMD基于蜣螂优化算法优化VMD变分模态分解时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.利用蜣螂优化算法优化VMD中的参数k、a&…

12、Kafka中位移提交那些事儿

Kafka中位移提交那些事儿 1、自动提交位移2、手动提交位移2.1、同步提交位移2.2、异步提交位移2.3、更精细化的位移管理 Consumer 端有个位移的概念,它和消息在分区中的位移不是一回事儿,虽然它们的英文都是 Offset。今天我们要聊的位移是 Consumer 的消…

千亿露酒市场的未来之“露”

执笔 | 尼 奥 编辑 | 扬 灵 12月15日,以“以美为酿,品致未来”为主题的中国露酒产业发展大会暨露酒价值论坛在“中国酒都”宜宾举办。 近年来,露酒产业发展异军突起,市场销售规模超越黄酒、葡萄酒品类,成为中国酒…

正则表达式IP地址

正则表达式基础语法 正则表达式-字符类 [abc]:代表a或者b,或者c字符中的一个。 [^abc]:代表除a,b,c以外的任何字符。 [a-z]:代表a-z的所有小写字符中的一个。 [A-Z]:代表A-Z的所有大写字符中的一个。 [0-9]&#xff…

人工智能文本分类

在本文中,我们全面探讨了文本分类技术的发展历程、基本原理、关键技术、深度学习的应用,以及从RNN到Transformer的技术演进。文章详细介绍了各种模型的原理和实战应用,旨在提供对文本分类技术深入理解的全面视角。 一、引言 文本分类作为人工…

期末总复习(重点!!!)

一、第6章异常处理 1、什么是异常、什么是异常处理异常是指程序在运行过程中发生的错误事件,影响程序的正常执行。异常并不是一定会发生,默认情况下,程序运行中遇到异常时将会终止,并在控制台打印出异常出现的堆栈信息。异常处理…

在线客服系统定价因素解析:影响价格的关键因素

跨境电子商务公司必不可少的工具就是在线客服系统。企业选择在线客服系统的时候免不了要对不同产品的功能性、价格、服务等因素进行考量。今天这篇文章,我们就来探讨一下在线客服系统的定价因素有哪些?探究市面上的在线客服系统价格各异的影响因素。为大…

Lambda 的表达式作用域(Lambda Scopes)

文章目录 讲一下 Lambda 的表达式作用域(Lambda Scopes)。访问局部变量访问字段和静态变量访问默认接口方法 讲一下 Lambda 的表达式作用域(Lambda Scopes)。 访问局部变量 我们可以直接在 lambda 表达式中访问外部的局部变量&a…

c# bitmap压缩导致png不透明的问题解决

新建.net 6控制台项目 安装System.Drawing.Common包 代码如下 using System.Drawing; using System.Drawing.Imaging;namespace PngCompress02 {internal class Program{static void Main(string[] args){CompressPngImage("E:\Desktop\6.png", "E:\Desktop\6…

C++相关闲碎记录(14)

1、数值算法 &#xff08;1&#xff09;运算后产生结果accumulate() #include "algostuff.hpp"using namespace std;int main() {vector<int> coll;INSERT_ELEMENTS(coll, 1, 9);PRINT_ELEMENTS(coll);cout << "sum: " << accumulate(…

DPDK系列之三十九控制管理

一、基础介绍 通过前面的分析&#xff0c;对DPDK中对报文处理的过程有了一个初步的认知。从一个更高层次来看&#xff0c;传统的网络通信一般会通过上层应用、操作系统、网卡驱动和硬件四层。再往下&#xff0c;基本就不属于于计算机控制的系统了。 早期的应用&#xff0c;基本…

Python - coverage

coverage overage 是一个用于测量Python程序代码覆盖率的工具。它监视您的程序&#xff0c;注意代码的哪些部分已经执行&#xff0c;然后分析源代码&#xff0c;以确定哪些代码本可以执行&#xff0c;但没有执行。 覆盖率测量通常用于衡量测试的有效性。它可以显示代码的哪些…

整理了上百个开源中文大语言模型,涵盖模型、应用、数据集、微调、部署、评测

自ChatGPT为代表的大语言模型&#xff08;Large Language Model, LLM&#xff09;出现以后&#xff0c;由于其惊人的类通用人工智能&#xff08;AGI&#xff09;的能力&#xff0c;掀起了新一轮自然语言处理领域的研究和应用的浪潮。 尤其是以ChatGLM、LLaMA等平民玩家都能跑起…

抖音品牌力不足,如何开通抖音旗舰店?强开旗舰店全攻略来了!

随着直播的兴起&#xff0c;抖音电商在近年来的发展速度可谓是相当迅猛。越来越多的商家开始将重心投入到抖音电商。从开店、搭建直播间&#xff0c;起号&#xff0c;再到日常运营... 然而我们在第一步开店的时候&#xff0c;就遇到了不少麻烦。 1、选择开通抖音旗舰店&#x…

初识Flask

摆上中文版官方文档网站&#xff1a;https://flask.github.net.cn/quickstart.html 开启实验之路~~~~~~~~~~~~~ from flask import Flaskapp Flask(__name__) # 使用修饰器告诉flask触发函数的URL&#xff0c;绑定URL&#xff0c;后面的函数用于返回用户在浏览器上看到的内容…

Spring Cloud + Vue前后端分离-第5章 单表管理功能前后端开发

Spring Cloud Vue前后端分离-第5章 单表管理功能前后端开发 完成单表的增删改查 控台单表增删改查的前后端开发&#xff0c;重点学习前后端数据交互&#xff0c;vue ajax库axios的使用等 通用组件开发:分页、确认框、提示框、等待框等 常用的公共组件:确认框、提示框、等待…