【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,一经查实,立即删除!

相关文章

【c++】string的模拟实现

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

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

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

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

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

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

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

人工智能文本分类

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

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

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

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(…

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…

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

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

系列九、事务

一、事务 1.1、概述 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或者撤销操作请求&#xff0c;即&#xff1a;这些操作要么同时成功&#xff0c;要么同时失败。 例如: 张三给李四转账1000块钱&…

使用邮件群发平台,轻松实现高效沟通的4大优势!

新媒体带动着众多线上平台的发展&#xff0c;使得流量为企业带来了可观的营收。但是&#xff0c;随着短视频市场的饱和&#xff0c;想要再次获得初始时的流量就变得越发困难。在这个时候&#xff0c;企业不妨将眼光往邮件群发这个传统的营销方式上倾斜&#xff0c;特别是出海、…

数据结构之---- 动态规划

数据结构之---- 动态规划 什么是动态规划&#xff1f; 动态规划是一个重要的算法范式&#xff0c;它将一个问题分解为一系列更小的子问题&#xff0c;并通过存储子问题的解来避免重复计算&#xff0c;从而大幅提升时间效率。 在本节中&#xff0c;我们从一个经典例题入手&am…

盛最多水的容器

给定一个长度为 n 的整数列表 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例1&…

Python基础01-环境搭建与输入输出

零、文章目录 Python基础01-环境搭建与输入输出 1、Python概述 &#xff08;1&#xff09;为什么要学习Python 技术趋势&#xff1a;Python自带明星属性&#xff0c;热度稳居编程语言界前三 简单易学&#xff1a;开发代码少&#xff0c;精确表达需求逻辑&#xff1b;33个关…

什么是Maven?

什么是Maven 1、Maven是依赖管理、项目构建工具。 pom.xml springBoot项目的核心配置文件&#xff0c;pom项目对象模型、Dependency依赖管理模型。 Maven中的GAVP是指&#xff1a; 1、GroupId&#xff1a;当前工程组织id&#xff0c;例如&#xff1a;com.jd.tddl 2、ArtifactI…

IS-IS原理与配置

IS-IS原理与配置 • IS-IS&#xff08;Intermediate System to Intermediate System&#xff0c;中间系统到中间系统&#xff09;是ISO &#xff08;International Organization for Standardization&#xff0c;国际标准化组织&#xff09;为它的CLNP &#xff08;ConnectionL…