解决多线程环境下单例模式同时访问生成多个实例
如何满足单例:1.构造方法是private、static方法、if语句判断
①、单线程
Single类
//Single类,定义一个GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {System.out.println("创建一次");}public static LazySingleton GetInstance() {//当多线程来临的时候判断是否为null,此时instance就是临界资源,会实例化多个if (instance == null) {instance = new LazySingleton();}return instance;}
}
//客户端代码
public class Main {public static void main(String[] args) {LazySingleton s1= LazySingleton.GetInstance();LazySingleton s2= LazySingleton.GetInstance();if(s1==s2){System.out.println("两个对象是相同的实例");}}
}
运行结果:

这样的话就满足了单例的效果,保证只实例化一个类,因为LazySingleton封装它的唯一实例,这样它可以严格地控制客户怎样访问它以及何时访问它。简单地说就是对唯一实例的受控访问。客户端通过那唯一可以访问的GetInstance方法来访问那一个实例。但如果是多个线程同时调用GetInstance方法,同时运行到了GetInstance方法这儿,它们都会去判断有没有被实例化,判断都为True,那样的话就创建了两个实例,就违背了单例模式,不是一个单例。看下多线程下的单例:
②、多线程
单例类
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {System.out.println("创建一次");}public static LazySingleton GetInstance() {//当多线程来临的时候判断是否为null,此时instance就是临界资源,会实例化多个if (instance == null) {instance = new LazySingleton();}return instance;}
}
main函数
public class Main {public static void main(String[] args) {Runnable r=()->{LazySingleton s1= LazySingleton.GetInstance();LazySingleton s2= LazySingleton.GetInstance();if(s1==s2){System.out.println("两个对象是相同的实例");}};//两个线程Thread t1= new Thread(r);Thread t2= new Thread(r);t1.start();t2.start();}
}
运行结果:

我们会发现对象被创建了两次,我们通过调试发现s1和s2两个对象的地址实际上是不一样的:

当线程t1刚执行完if (instance == null)判断之后时间片到了,t2线程执行完if (instance == null)判断之后就进入方法体生成了实例,此时t1线程又获得了时间片,t1会接着上次中断的地方继续执行,t1线程便会进入方法体又生成了一个新的实例,此时t1和t2线程各生成了一个实例
如何解决这样一个问题呢?
添加锁,当线程位于临界区的时候就上锁,其他线程来临的时候只能在外排队等待。
③、多线程单例——单锁
单例类
package com.example;public class LazySingleton {private static LazySingleton instance;private LazySingleton() {System.out.println("创建一次");}public static LazySingleton GetInstance() {//当多线程来临的时候判断是否为null,此时instance就是临界资源,会实例化多个//方法:加锁-把判断的这部分逻辑上锁synchronized ("") {if (instance == null) {instance = new LazySingleton();}}return instance;}}
main函数
public class Main {public static void main(String[] args) {Runnable r=()->{LazySingleton s1= LazySingleton.GetInstance();LazySingleton s2= LazySingleton.GetInstance();if(s1==s2){System.out.println("两个对象是相同的实例");}};//两个线程Thread t1= new Thread(r);Thread t2= new Thread(r);t1.start();t2.start();}
}
运行结果:

发现对象创建了一次。在同一时刻加了锁的那部分程序只有一个线程可以进入,我们可以让最先进入的那个线程先上一把锁,创建实例。后面在进入的线程就不会再去创建对象实例了,因为第一名来的线程已经创建了,你这个判断的结果是False,自然无法创建了。这样的话就保证了多个线程同时访问的话不会有多个实例化。解决了上面单实例带来的问题。但每次进入的线程都需要先加锁在判断,我都还不知道有没有创建过这个实例呢你就让我加锁,第一名已经实例化过了,我进去再加锁,在判断一次,如果有上百个线程同时访问呢,这样的工作重复上百次,不是很影响我这个程序的性能吗?我们就可以用到双重锁定来解决这个问题
④、多线程——双重锁(Double-Check Locking)
package com.example;public class DoubleLockSingleton {private static DoubleLockSingleton instance;private DoubleLockSingleton() {System.out.println("实例化了一次");}public static DoubleLockSingleton GetInstance() {//第一层判断:先判断实例是否存在,不存在再加锁处理if (instance == null) {synchronized ("") {//第二层判断if (instance == null) {instance = new DoubleLockSingleton();}}}return instance;}
}
通过这样两重的判断,进入的线程不用每次都加锁,只是在实例未被创建的时候在加锁处理。同时也保证多线程的安全。
相关文章:
解决多线程环境下单例模式同时访问生成多个实例
如何满足单例:1.构造方法是private、static方法、if语句判断 ①、单线程 Single类 //Single类,定义一个GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例 public class LazySi…...
转转闲鱼交易猫源码搭建
后台一键生成链接,独立后台管理 教程:修改数据库config/Conn.php 不会可以看源码里有教程 下载程序:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3...
设计模式精华版汇总
以下是个人整理的设计模式汇总,将会持续更新工作和面试中经常用到的设计模式。 设计模式-装饰者模式(包装模式)- 案例分析和源码分析 设计模式-代理模式:控制访问的设计模式 - 案例分析 设计模式-门面模式…...
uniapp实现带参数二维码
view <view class"canvas"><!-- 二维码插件 width height设置宽高 --><canvas canvas-id"qrcode" :style"{width: ${qrcodeSize}px, height: ${qrcodeSize}px}" /></view> script import uQRCode from /utils/uqrcod…...
金融行业软件测试面试题及其答案
下面是一些常见的金融行业软件测试面试题及其答案: 1. 什么是金融行业软件测试? 金融行业软件测试是针对金融领域的软件系统进行验证和确认的过程,旨在确保软件在安全、稳定、可靠和符合法规要求的条件下运行。 2. 解释一下金融软件中的风险…...
强化学习QLearning 进行迷宫游戏和代码
强化学习是机器学习里面的一个分支。它强调基于环境而探索行动、学习,以取得最大化的预期收益。其灵感来源于心理学中的行为主义理论,既有机体如何在环境给予的奖励或者惩罚的刺激下,逐步形成对刺激的预期,产生能够最大利益的习惯…...
Vue2 第九节 过滤器
(1)定义:对要显示的数据进行特定格式化后再显示 (2)语法: ① 注册过滤器 1)Vue.filter(name, callback) 全局过滤器 2) new Vue({filters:{}}) 局部过滤器 ② 使用过滤器 1&…...
Swift 对象数组去重
使用 reduce 方法去重 使用 reduce 方法结合 contains 方法可以实现去重。reduce 方法用于将数组的元素进行累积计算,而 contains 方法用于检查元素是否已经存在于结果数组中。 struct SearchRecord: Equatable {let id: Intlet name: String }let records [Sear…...
代码随想录算法训练营day52 300.递增子序列 674.最长连续递增子序列 718.最长重复子数组
题目链接300.递增子序列 class Solution {public int lengthOfLIS(int[] nums) {int[] dp new int[nums.length];Arrays.fill(dp, 1);for(int i 0; i < nums.length; i){for(int j 0; j < i; j){if(nums[i] > nums[j]){dp[i] Math.max(dp[i], dp[j] 1);}}}int r…...
Android 面试题 虚拟机、进程、线程 七
🔥 安卓虚拟机 🔥 虽然Android程序是使用Java语言开发的,当然,现在也可以使用kotlin语言。但是实际上我们开发出来的Android程序并不能运行在JVM上,而是只能运行在一个类似JVM的Android虚拟机上。Android虚拟机有两种&…...
Flutter 状态组件 InheritedWidget
Flutter 状态组件 InheritedWidget 视频 前言 今天会讲下 inheritedWidget 组件,InheritedWidget 是 Flutter 中非常重要和强大的一种 Widget,它可以使 Widget 树中的祖先 Widget 共享数据给它们的后代 Widget,从而简化了状态管理和数据传递…...
<C++> 入门
在学习完C语言的基础上,继续开始C的学习。 C是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等。熟悉C语言之后,对C学习有一定的帮助。 1. 补充C语言语法的不足,以及C是如…...
政策加持智能家居市场,涂鸦赋能客户打造“以人为本”智能生活新方式
7月18日,商务部等13部门联合发布了《关于促进家居消费若干措施的通知》(以下简称《通知》),《通知》指出,创新培育智能消费,支持企业运用物联网、云计算、人工智能等技术,着重加快智能家电、智能…...
安全渗透初级知识总结-2
CIA三原则:保密性,完整性,可用性 https:解决了安全传输问题 核心技术:用非对称加密传输对称加密的秘钥,然后用对称秘钥通信 抓包:Wireshark、tshark、tcpdump valueof方法是一个所有对象都拥有的方法&am…...
数学建模的32种常规方法及案例代码
比赛期间整理的数学建模的32种常规方法及案例代码友情分享: 链接:https://pan.baidu.com/s/18uDr1113a0jhd2No8O1Nog 提取码:xae5 在数学建模中,常规算法是指那些被广泛应用于各种问题求解的经典算法。这些算法覆盖了不同的数学…...
【Django+Vue】英文成绩管理平台--20230727
能够满足大部分核心需求(标绿):报表部分应该比较难。 项目地址 前端编译 https://gitlab.com/m7840/toeic_vue_dist Vue源码 https://gitlab.com/m7840/toeic_vue Django源码 https://gitlab.com/m7840/toeic_python 项目架构 流程 …...
栈-模拟栈
实现一个栈,栈初始为空,支持四种操作: push x – 向栈顶插入一个数 x; pop – 从栈顶弹出一个数; empty – 判断栈是否为空; query – 查询栈顶元素。 现在要对栈进行 M 个操作,其中的每个…...
图观| 从王宝强、费翔、阿汤哥等新上映的电影聊聊图的智能推荐场景
从技术的视角来看,推荐系统本质上是在用户需求不明确的情况下,从海量的信息中为用户过滤出他可能感兴趣的信息的一种技术手段。 我们日常接触到的智能推荐有: 电商网站:如淘宝、天猫、京东、Amazon…… 生活服务:如美…...
Redis系列一:介绍
介绍 The open source, in-memory data store used by millions of developers as a database, cache, streaming engine, and message broker. 相关资源 Redis 官网:https://redis.io/ 源码地址:https://github.com/redis/redis Redis 在线测试&#…...
Java 设计模式 - 单例模式 - 保证类只有一个实例
单例模式 - 保证类只有一个实例 为什么使用单例模式?单例模式的实现方式1. 饿汉式(Eager Initialization)2. 懒汉式(Lazy Initialization)3. 双重检查锁(Double-Checked Locking)4. 静态内部类&…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
WEB3全栈开发——面试专业技能点P7前端与链上集成
一、Next.js技术栈 ✅ 概念介绍 Next.js 是一个基于 React 的 服务端渲染(SSR)与静态网站生成(SSG) 框架,由 Vercel 开发。它简化了构建生产级 React 应用的过程,并内置了很多特性: ✅ 文件系…...
前端工具库lodash与lodash-es区别详解
lodash 和 lodash-es 是同一工具库的两个不同版本,核心功能完全一致,主要区别在于模块化格式和优化方式,适合不同的开发环境。以下是详细对比: 1. 模块化格式 lodash 使用 CommonJS 模块格式(require/module.exports&a…...
