单例模式:双重锁校验可能存在的问题。
来源:互联网 发布:域名还要买 编辑:程序博客网 时间:2024/06/05 23:04
参考文章:http://www.cnblogs.com/chenssy/p/6379280.html
一、volatile的作用
在《Java并发编程:核心理论》一文中,我们已经提到过可见性、有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果对Synchronized原理有了解的话,应该知道Synchronized是一个比较重量级的操作,对系统的性能有比较大的影响,所以,如果有其他解决方案,我们通常都避免使用Synchronized来解决问题。而volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案。对于原子性,需要强调一点,也是大家容易误解的一点:对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量,但是并不能保证i++这种操作的原子性,因为本质上i++是读、写两次操作。
二、volatile的使用
1、防止重排序
我们从一个最经典的例子来分析重排序问题。大家应该都很熟悉单例模式的实现,而在并发环境下的单例实现方式,我们通常可以采用双重检查加锁(DCL)的方式来实现。其源码如下:
1 package com.paddx.test.concurrent; 2 3 public class Singleton { 4 public static volatile Singleton singleton; 5 6 /** 7 * 构造函数私有,禁止外部实例化 8 */ 9 private Singleton() {};10 11 public static Singleton getInstance() {12 if (singleton == null) {13 synchronized (singleton) {14 if (singleton == null) {15 singleton = new Singleton();16 }17 }18 }19 return singleton;20 }21 }
现在我们分析一下为什么要在变量singleton之间加上volatile关键字。要理解这个问题,先要了解对象的构造过程,实例化一个对象其实可以分为三个步骤:
(1)分配内存空间。
(2)初始化对象。
(3)将内存空间的地址赋值给对应的引用。
但是由于操作系统可以对指令进行重排序,所以上面的过程也可能会变成如下过程:
(1)分配内存空间。
(2)将内存空间的地址赋值给对应的引用。
(3)初始化对象
如果是这个流程,多线程环境下就可能将一个未初始化的对象引用暴露出来,从而导致不可预料的结果。因此,为了防止这个过程的重排序,我们需要将变量设置为volatile类型的变量。
- 单例模式:双重锁校验可能存在的问题。
- 单例模式--双重校验锁
- 单例模式 双重校验锁
- Java带有双重校验锁的单例模式
- 单例模式双重校验的再理解
- 单例模式的双重检测问题
- 单例模式双重检查锁问题
- 【Java 单例模式】Java 单例模式在多线程环境中可能存在的问题
- Java单例模式中双重检查锁的问题
- Java单例模式中双重检查锁的问题
- Java单例模式中双重检查锁的问题
- 单例模式的五种写法:饿汉,懒汉, 双重校验锁,静态内部类,枚举
- 设计模式--单例模式(二)双重校验锁模式
- Java设计模式——单例模式(双重校验锁)
- java单例模式的5种写法-饿汉、懒汉、静态内部类、双重校验锁、枚举
- 理解单例设计模式(饿汉式,懒汉式,静态内部类,枚举,双重校验锁)
- 多线程下安全的单例模式(双重校验锁实现,登记者模式实现,利用内部类实现,利用枚举实现)
- Java--单例模式(双重锁的形式)
- php杂项函数总汇(很实用的未归类函数)
- 2018大疆校招软件岗位笔试题目(求有效工作时间)——未在线验证
- 串口操作经验总结
- contiki之uip-ds6-route头文件
- LintCode:M-不同的二叉查找树个数
- 单例模式:双重锁校验可能存在的问题。
- Java 多线程join方法
- 编译选项默认关闭adb RSA指纹认证
- Csharp进阶:文件流之Directory类和DirectoryInfo类,FileStream 类
- 求逆序对
- 19_字符串移位包含问题
- tableViewCell设置底部线长度与屏幕等宽(备忘)
- hdu2966 In case of failure(这道题就和ta的name一样,failure)
- Datatable回到当前页