背景&问题

在早期的JVM中,synchronized存在巨大的性能开销。因此,有人想出了一个“聪明”的技巧:双重检查锁定(Double-Checked Locking)。人们想通过双重检查锁定来降低同步的开销。下面是使用双重检查锁定来实现延迟初始化的示例代码。

public class DoubleCheckedLocking { // 1
private static Instance instance; // 2
public static Instance getInstance() { // 3
if (instance == null) { // 4:第一次检查
synchronized (DoubleCheckedLocking.class) { // 5:加锁
if (instance == null) // 6:第二次检查
instance = new Instance(); // 7:问题的根源出在这里
} // 8
} // 9
return instance; // 10
} // 11
}

上述的Instance类变量是没有用volatile关键字修饰的,会导致这样一个问题:

在线程执行到第4行的时候,代码读取到instance不为null时,instance引用的对象有可能还没有完成初始化。

原因

主要的原因是重排序。重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。

第7行的代码创建了一个对象,这一行代码可以分解成3个操作:

memory = allocate();  // 1:分配对象的内存空间
ctorInstance(memory); // 2:初始化对象
instance = memory;  // 3:设置instance指向刚分配的内存地址

根源在于代码中的2和3之间,可能会被重排序。例如:

memory = allocate();  // 1:分配对象的内存空间
instance = memory;  // 3:设置instance指向刚分配的内存地址
// 注意,此时对象还没有被初始化!
ctorInstance(memory); // 2:初始化对象java

这在单线程环境下是没有问题的,但在多线程环境下会出现问题:B线程会看到一个还没有被初始化的对象。

A2和A3的重排序不影响线程A的最终结果,但会导致线程B在B1处判断出instance不为空,线程B接下来将访问instance引用的对象。此时,线程B将会访问到一个还未初始化的对象。

改进

所以只需要做一点小的修改(把instance声明为volatile型),就可以实现线程安全的延迟初始化。因为被volatile关键字修饰的变量是被禁止重排序的。

单例模式中volatile关键字的作用的更多相关文章

  1. Java中volatile关键字及其作用是什么?

    在 Java 多线程中如何保证线程的安全性?那我们可以使用 Synchronized 同步锁来给需要多个线程访问的代码块加锁以保证线程安全性.使用 synchronized 虽然可以解决多线程安全问题 ...

  2. Java 中 volatile 关键字及其作用

    引言 作为 Java 初学者,几乎从未使用过 volatile 关键字.但是,在面试过程中,volatile 关键字以及其作用还是经常被面试官问及.这里给各位童靴讲解一下 volatile 关键字的作 ...

  3. Java内存模型中volatile关键字的作用

    volatile作用总结: 1. 强制线程从公共内存中取得变量的值,而不是从线程的私有的本地内存中,volatile修饰的变量不具有原子性(修改一个变量的值不能同步). 2. 保证volatile修饰 ...

  4. 多线程中volatile关键字的作用

    原文链接:https://blog.csdn.net/xuwentao37x/article/details/27804169 多线程的程序是出了名的难编写.难验证.难调试.难维护,这通常是件苦差事. ...

  5. 深入解析Java中volatile关键字的作用

    转(http://m.jb51.net/article/41185.htm)Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制 在java线 ...

  6. java中volatile关键字的作用

    一.内存模型的相关概念 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存 ...

  7. volatile关键字的作用、原理

    在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到"半个"单例. 而发挥神奇作用的volatile,可以当之 ...

  8. 面试题:volatile关键字的作用、原理

    在只有双重检查锁,没有volatile的懒加载单例模式中,由于指令重排序的问题,我确实不会拿到两个不同的单例了,但我会拿到“半个”单例. 而发挥神奇作用的volatile,可以当之无愧的被称为Java ...

  9. Java并发编程学习笔记 深入理解volatile关键字的作用

    引言:以前只是看过介绍volatile的文章,对其的理解也只是停留在理论的层面上,由于最近在项目当中用到了关于并发方面的技术,所以下定决心深入研究一下java并发方面的知识.网上关于volatile的 ...

随机推荐

  1. [RK3399] Jack server installation not found

    CPU:RK3399 系统:Android 7.1 服务器上第一次编译 Android 7.1 的代码,提示 Jack server 没有安装. Jack server installation no ...

  2. EL表达式 与 JSTL标准标签库

    目录 EL表达式 什么是EL表达式 作用 EL内置11对象 EL执行表达式 JSTL 什么是JSTL JSTL标准标签库有5个子库 把JSTL标签库jar包引入工程当中 if标签 foreach标签 ...

  3. java打jar包与找不到依赖包详解

    eclipse打jar包与找不到依赖包详解 eclipse打工具jar 1.项目右键-->export -->搜索java 2.选择JAR file 3.打包 eclipse打包可执行ja ...

  4. C++ STL介绍——String类

    目录 1.简介 2.string类成员函数汇总 3.String类的构造函数以及析构函数 4.获取字符串长度 5.获取字符串元素 6.字符串比较方法 7.字符串输入输出 8.字符串查找函数 1.简介 ...

  5. OpenTK学习笔记(3)-你好!窗体!

    参考:http://dreamstatecoding.blogspot.com/2017/01/opengl-4-with-opentk-in-c-part-1.html http://www.cnb ...

  6. Microsoft Visual C++ Runtime library not enough space for thread data

    Microsoft Visual C++ Runtime library not enough space for thread data     电脑最近一直在运行的时候,弹出提示框,如下: 解决办 ...

  7. linux内核中IS_ALIGNED是如何定义的?

    1. 定义如下: (include/linux/kernel.h) #define IS_ALIGNED(x, a)                (((x) & ((typeof(x))(a ...

  8. 【React自制全家桶】一、Webstrom+React+Ant Design+echarts搭建react项目

    前言 一.React是Facebook推出的一个前端框架,之前被用于著名的社交媒体Instagram中,后来由于取得了不错的反响,于是Facebook决定将其开源.出身名门的React也不负众望,成功 ...

  9. connections java.net.BindException: Address already in use_解决方案

    一.问题描述 在Linux服务器(CentOS7系统)中配置并启动JMeter远程监控服务器资源所需的ServerAgent目录下的 startAgent.sh 文件时,系统出现异常提示,如 [roo ...

  10. JVM参数详细说明

    JVM参数详细说明   答: 下面红色部分是常用参数 -XX:CMSInitiatingPermOccupancyFraction:当永久区占用率达到这一百分比时,启动CMS回收-XX:CMSInit ...