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

Spring常用设计模式-实战篇之单例模式

  实现案例,饿汉式 + Double-Check机制 + synchronized锁

/*** 以饿汉式为例* 使用Double-Check保证线程安全*/
public class Singleton {// 使用volatile保证多线程同一属性的可见性和指令重排序private static volatile Singleton instance;public static Singleton getInstance() {// 第一次checkif (instance == null) {synchronized (Singleton.class) {// 第二次checkif (instance == null) {instance = new Singleton();}}}return instance;}}

1、两次check的作用

第一次check:为了提高效率,假如我的instance已经不为null了,就没必要进入同步代码块了;

第二次check:因为在没有获取实例之前,即instance为null之前,可能有多个线程进入了第一个if之内,这个时候为了防止创建多个实例,使用同步代码块,一个线程一个线程进入,当Instance不为null时,才new对象,保证了对象实例只被 new 一次,即保证单例模式。

2、为什么使用了synchonized同步还要加volatile关键字

 首先,synchonized可以保证原子性和可见性,但是他保证不了指令重排序这种情况。

 那指令重排序存在什么问题呢?

当线程A和B分别执行到以上位置时,

 1)对于  instance = new Singleton(); 这个操作,其实分为三个步骤:

  1. JVM为对象分配一块内存;
  2. 在内存上为对象进行初始化;
  3. 将内存的地址赋值给singleton变量;

这样是没有问题的,因为只有把内存地址赋值给singleton变量以后,instance才不等于null,而赋值之前就已经初始化了,所以线程B不会出现误判的情况;

2)但是假如不使用volatile,编译器可能会优化,将2,3替换位置,也就是:

  1. JVM为对象分配一块内存;
  2. 将内存的地址赋值给singleton变量;
  3. 在内存上为对象进行初始化;

这样就可能会出现问题了,场景如下:

        当A线程赋值了以后,还没来得及初始化呢,这个时候线程B刚好判断instance == null,返回false,直接return instance了,但此时这个instance实际上是还没初始化的bean,这样就有问题了。

总结

  1. 懒汉式是线程不安全的,可以通过synchonized进行加锁,保证它的一个线程安全性;
  2. 如果你想提高它的效率,可以使用Double-Check这种机制,让它存在实例以后无需再去竞争锁,在外层 if 即可直接判断;
  3. 当你使用Double-Check这种机制的时候,请注意加上volatile关键字,防止优化器指令重排序带来的影响。

ps:以下是我整理的java面试资料,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!

链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java面试宝典》 

相关文章:

  • vue父子组件生命周期
  • vue3 + ts +element-plus + vue-router + scss + axios搭建项目
  • O2OA(翱途)开发平台前端安全配置建议(一)
  • Ubuntu学习笔记之Shell与APT下载工具
  • 数据结构-双向链表-003
  • Eclipse For ABAP:安装依赖报错
  • python共享单车信息系统的设计与实现flask-django-php-nodejs
  • U盘插入电脑没有显示怎么办?
  • 适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼
  • Play on Words(UVA 10129)
  • java获取数据库信息为空解决方案
  • 一、初识 Web3
  • 【题目】【网络系统管理】2019年全国职业技能大赛高职组计算机网络应用赛项H卷
  • html5cssjs代码 036 CSS默认值
  • sentinel系统规则
  • [iOS]Core Data浅析一 -- 启用Core Data
  • “大数据应用场景”之隔壁老王(连载四)
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Go 语言编译器的 //go: 详解
  • JavaScript函数式编程(一)
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 笨办法学C 练习34:动态数组
  • 代理模式
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 聚簇索引和非聚簇索引
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 入门级的git使用指北
  • 使用Gradle第一次构建Java程序
  • 算法-图和图算法
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 我的业余项目总结
  • 一个完整Java Web项目背后的密码
  • 赢得Docker挑战最佳实践
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • 国内开源镜像站点
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • ​2021半年盘点,不想你错过的重磅新书
  • #HarmonyOS:基础语法
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • (007)XHTML文档之标题——h1~h6
  • (1)虚拟机的安装与使用,linux系统安装
  • (4)STL算法之比较
  • (poj1.2.1)1970(筛选法模拟)
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (办公)springboot配置aop处理请求.
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)RocketMQ初步认识
  • (一)插入排序
  • (转)视频码率,帧率和分辨率的联系与区别
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1