-
设计模式系列-单例模式
是什么?
定义: 确保一个类只有一个实例,并且提供访问该实例的静态方法。
单例的特点:
- 在JVM中有且只能有一个实例存在。
-
构造器必须私有(
private修饰
),禁止外部类通过构造器创建。 -
提供一个全局公开的
getInstance()
方法获取该实例。
饿汉式 - 线程安全
饿汉式,简单理解就是比较饿,事先就迫不及待创建好实例, 然后调用 get 方法的时候,直接返回该实例即可。
直接创建:
静态代码块创建:
因为是事先创建好实例,所以没有线程安全问题。
懒汉式 - 线程不安全
懒汉式,可以理解为它懒,只有到真正要用到实例的时候,它才会去创建。
简单实现 ~~
这种写法会有会有线程问题
, 如果多个线程都执行到 if(lhSingleton == null)
并且通过,那么就会创建多个实例。
要解决这个问题也简单,给 getInstance()
方法加锁就行了,保证同一时刻只有一个线程获取实例。即可。说干就干 ~~
这样是比较干脆的解决了线程安全问题。
这样做有个缺点,就是已经有实例了,每次调用还是要加锁排队,极大的影响性能。不推荐这样写。
我们要做到,只有最开始需要创建实例的时候,才加锁同步。那继续优化吧 ~~ 也就是双检锁了!
双检锁 - 线程安全
- 先检查实例是否已存在,不存在才加锁
- 考虑到有多个线程会通过第一次的判断, 即使加了锁,这些线程依旧会排队执行同步代码块中的创建实例逻辑,还是可能会创建多次的,所以需要在同步代码块种进行二次判断。
sjsSingleton 采用 volatile 关键字修饰也是很有必要的, sjsSingleton = new SJSSingleton();
这段代码其实分为三步执行:
- 为 sjsSingleton 实例在堆中分配内存空间
- 初始化 sysSingleton
- 将 jssSingleton 指向分配的内存地址
但是由于 JVM 具有指令重排序的特性,执行顺序可能变成1>3>2。指令重排在单线程环境下不会出现问题,但是在多线程环境下,会导致一个线程获得还没有初始化的实例。
使用 volatile 可以禁止 JVM 指令重排, 保证在多线程环境下也能正常运行。
volatile 除了禁止JVM 指令重排之外,还可以保证变量内存可见性,想具体了解,可以去查看相关资料!
本文由博客一文多发平台 OpenWrite 发布!
__EOF__
最新更新
求1000阶乘的结果末尾有多少个0
详解MyBatis延迟加载是如何实现的
IDEA 控制台中文乱码4种解决方案
SpringBoot中版本兼容性处理的实现示例
Spring的IOC解决程序耦合的实现
详解Spring多数据源如何切换
Java报错:UnsupportedOperationException in Col
使用Spring Batch实现批处理任务的详细教程
java中怎么将多个音频文件拼接合成一个
SpringBoot整合ES多个精确值查询 terms功能实
数据库审计与智能监控:从日志分析到异
SQL Server 中的数据类型隐式转换问题
SQL Server中T-SQL 数据类型转换详解
sqlserver 数据类型转换小实验
SQL Server数据类型转换方法
SQL Server 2017无法连接到服务器的问题解决
SQLServer地址搜索性能优化
Sql Server查询性能优化之不可小觑的书签查
SQL Server数据库的高性能优化经验总结
SQL SERVER性能优化综述(很好的总结,不要错
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比