volatile禁止重排使用场景与单例模式的Double Check Lock
普通单例模式Demo
public class Demo{
private static Demo INSTANCE;
private Demo(){}
public static Demo getInstance(){
if(INSTANCE==null){
// 饿汉式单例
INSTANCE=new Demo();
}
return INSTANCE;
}
}
上面单例实现方式在单线程访问下没有问题,但是在并发访问时,会产生多个对象。
如程序启动 A线程获取INSTANCE执行完if判断为null后,线程B获取到CPU执行权并完成if判断和INSTANCE实例化得到时列对象,当A线程再次获得执行权后执行if中语句,又会创建一个新对象并对INSTANCE赋值,此时A,B得到的为两个不同的对象。
多线程版单列模式
public class Demo{
private static Demo INSTANCE;
private Demo(){}
public static synchronized Demo getInstance(){
if(INSTANCE==null){
INSTANCE=new Demo();
}
return INSTANCE;
}
}
使用synchronized关键字加锁(锁对象是Demo.class对象),保证了每次只会有一个线程执行方法。
虽然上述程序已不会出现使用问题,但是直接对整个方法进行锁定太过粗暴,作为高雅人士应该使用更优雅的方式实现锁定。
优化多线程版单列模式
public class Demo{
private static Demo INSTANCE;
private Demo(){}
public static Demo getInstance(){
if(INSTANCE==null){
synchronized (Demo.class){
// 锁细化
if(INSTANCE==null){
// 双重检查避免再次创建对象
INSTANCE=new Demo();
}
}
}
return INSTANCE;
}
}
对要逐个执行的功能锁定,对锁细化节省同步时间提高执行效率。
此时功能已经接近完美,但是对于超高并发的任务来说并不安全
如INSTANCE=new Demo()这句代码,编译后将会拆分出多个指令(以下只取三个关键指令描述)
- 初始化对象成员变量并赋默认值
- 将为我们要赋值给成员变量的值替换掉默认值
- 将对象的地址赋值给对应的引用
由于CPU存在指令重排的优化机制,在多线程访问时可能会影响到我们的执行结果,如下将2,3指令掉个顺序
- 初始化对象成员变量并赋默认值
- 将对象的地址赋值给对应的引用
- 将为我们要赋值给成员变量的值替换掉默认值
此时,按照我们优化过的单列模式进行超高并发任务时可能会出现意想不到的结果。
如:线程A执行,获取到锁对象进行INSTANCE=new Demo()对对象进行初始化,执行1,2后此时INSTANCE已经有指向的对象,但是对象的初始化还未完成,然后线程B执行进行第一次if(INSTANCE==null)判断,此时INSTANCE非null,获得对象,那么在线程A对对象默认值替换的3操作未完成时,线程B对INSTANCE对象的成员变量进行的操作都是存在问题的。
多线程版单列模式终极版
public class Demo{
private static volatile Demo INSTANCE; // 使用volatile 关键字禁止对指令进行重排
private Demo(){}
public static Demo getInstance(){
if(INSTANCE==null){
synchronized (Demo.class){
// 锁细化
if(INSTANCE==null){
// 双重检查避免再次创建对象
INSTANCE=new Demo();
}
}
}
return INSTANCE;
}
}
使用volatile修饰INSTANCE对象,那么CPU对该对象的操作将不会再进行指令重排,确保了对象初始化完成,并最后一步返回对象的地址给引用,达到万无一失的情况。
volatile禁止重排使用场景与单例模式的Double Check Lock的更多相关文章
- 对volatile的理解--从JMM以及单例模式剖析
请谈谈你对volatile的理解 1.volitale是Java虚拟机提供的一种轻量级的同步机制 三大特性1.1保证可见性 1.2不保证原子性 1.3禁止指令重排 首先保证可见性 1.1 可见性 概念 ...
- 【并发编程】Volatile原理和使用场景解析
目录 一个简单列子 Java内存模型 缓存不一致问题 并发编程中的"三性" 使用volatile来解决共享变量可见性 volatile和指令重排(有序性) volatile和原子性 ...
- Volatile禁止指令重排序(三)
Volatile禁止指令重排 计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下三种: 源代码 -> 编译器优化的重排 -> 指令并行的重排 -> 内存系 ...
- 单例模式+volatile禁止指令重排序
单例模式: 单例,顾名思义就是只能有一个.不能再出现第二个.就如同地球上没有两片一模一样的树叶一样. 在这里就是说:一个类只能有一个实例,并且整个项目系统都能访问该实例. 单例模式共分为两大类: 懒汉 ...
- volatile原理和应用场景
volatile是java语言中的一个关键字,常用于并发编程,有两个重要的特点:具有可见性,java虚拟机实现会为其满足Happens before原则;不具备原子性.用法是修饰变量,如:volati ...
- 单例模式的两种实现方式对比:DCL (double check idiom)双重检查 和 lazy initialization holder class(静态内部类)
首先这两种方式都是延迟初始化机制,就是当要用到的时候再去初始化. 但是Effective Java书中说过:除非绝对必要,否则就不要这么做. 1. DCL (double checked lockin ...
- 由单例模式学到:lock锁
lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁. lock (xxx) { // Critical code section. } lock 关键字可确保当一 ...
- double check 解决单例模式的多线程并发问题
最近被多线程问题(multi-thread issue)弄昏了头.以前虽然也知道系统里要考虑多线程问题,也无数次见到double-check的代码,但是由于自己碰到这方面的问题基本上就是从其他地方 ...
- Java程序员面试必备:Volatile全方位解析
前言 volatile是Java程序员必备的基础,也是面试官非常喜欢问的一个话题,本文跟大家一起开启vlatile学习之旅,如果有不正确的地方,也麻烦大家指出哈,一起相互学习~ 1.volatile的 ...
随机推荐
- [CF160D]Edges in MST (最小生成树+LCA+差分)
待填坑 Code //CF160D Edges in MST //Apr,4th,2018 //树上差分+LCA+MST #include<cstdio> #include<iost ...
- 适合 C++ 新手学习的开源项目——在 GitHub 学编程
作者:HelloGitHub-小鱼干 俗话说:万事开头难,学习编程也是一样.在 HelloGitHub 的群里,经常遇到有小伙伴询问编程语言如何入门方面的问题,如: 我要学习某一门编程语言,有什么开源 ...
- 写时复制集合 —— CopyOnWriteArrayList
前言 JUC 下面还有一个系列的类,都是 CopyOnWriteXXX ,意思是写时复制,这个究竟是怎么回事?那就以 CopyOnWriteArrayList 为切入点,一起了解写时复制是怎么回事? ...
- 转载-Eclipse导入第三方库的方法
作者:wyf_phper 原文:https://blog.csdn.net/qq_32985981/article/details/49976193 一:导入*.jar包步骤:将下载好的jar包复制到 ...
- 分享JDK解压版(ZIP)
目录 由于安装版本的jdk不太方便,所以我分享一下如何去获取解压版的jdk,jdk配置的话看这个文章 一.先下载exe版本的jdk安装程序: 二.使用7-ZIP解压工具 2.1 JDK8的解压目录 2 ...
- 通俗易懂浅谈理解ES6类this不同指向问题
1. class Btn{ //定义的一个类 constructor(id){ // constructor是一个构造函数,是一个默认方法,通过 new 命令创建对象实例时,自动调用该方法.一个类必须 ...
- 【Kata Daily 191010】Grasshopper - Summation(加总)
题目: Summation Write a program that finds the summation of every number from 1 to num. The number wil ...
- Python之Matplot——01.堆叠柱状图的绘制
1.Matplotlib是python的一个绘图库,可以方便的绘制各种图标,是数据可视化的利器. 2.本文我就给大家介绍一下条形图或者说柱状图的绘制 3.代码如下: <1>首先导入模块 1 ...
- linux 图解笔记
- 利用虚拟化环境虚拟nvme盘
前情介绍 SPDK SPDK的全称为Storage Performance Development Kit ,是Intel发起的一个开源驱动项目,这个是一个开发套件,可以让应用程序在用户态去访问存储资 ...