双重校验锁 -- Java并发编程中的陷阱
来源:互联网 发布:oracle数据库日志位置 编辑:程序博客网 时间:2024/06/04 14:39
今天在回顾volatile关键字的使用的时候,突然注意到其适用场景里有这么一个概念:双重校验锁(DCL)
那么他是什么意思呢?其实它的起源可以联系到单例模式的应用。
import java.util.*;class Singleton{ private static Singleton instance; //... private boolean flag; private Singleton() { //... flag= true; }//单线程下的获取实例 public static Singleton getInstance() { if (instance == null) //1 instance = new Singleton(); //2 return instance; //3 }}//多线程下获取实例1(正确)public static synchronized Singleton getInstance(){ if (instance == null) instance = new Singleton(); return instance; }//多线程下获取实例2(双重校验)public static Singleton getInstance(){ if (instance == null){ synchronized(instance.class){ if(instance == null) instance = new Singleton(); } } return instance; }
为什么多线程情况下获取实例的第二个双重校验方法会达不到要求呢?
其实这涉及到JVM编译器的工作,其内存模型允许指令无序写入,也就是可能会对指令进行重排序,从而导致在双重校验的方法中:执行
instance = new Singleton();
的时候,按照我们的理解应当是首先产生一个实例对象(初始化完成),随后再进行赋值,然而实际上并不一定是这样进行的,JVM可能在产生了一个空的实力对象之后就进行了赋值,操作,随后再进行(构造函数)初始化操作。如果另一个线程在空实例产生之后,初始化完成之前进行获取实例,其就会因为第一个if判断中就因为条件为true,而返回空的实例,产生错误。
- 上述中的第一个正确方法是怎么解决这个问题的呢?
其实很简单,就是给整个方法加了个锁,保证每次只有一个方法得以执行该方法,也就保证最终获得的实例一定是初始化之后的了。 - 前文我们也讲了,是在看volatile 关键字的时候看到这个问题的,那么volatile 是怎么解决这个问题的呢?
上面那种方法其实并不高效,在JDK1.5之后,我们可以使用volatile关键字来解决,volatile的特性之一就是禁止指令重排序(内存屏障的概念)。
PS:添加一下单例模式的实现代码
// 1、懒汉式 只适合单线程public class Singleton{ private static Singleton instance; //... private Singleton(){ //... } public static Singleton getInstance(){ if(instance == null) instance= new Singleton (); return instance;}//2、懒汉式 可用于多线程 效率低下 一般情况下不需要同步public class Singleton{ private static Singleton instance; //... private Singleton (){ //... } private static synchronized Singleton getInstance(){ if(instance == null) instance= new Singleton (); return instance; }}//3、饿汉式 在类装载的时候实例化 但是可能会有其他导致类加载 public class Singleton { private static Singleton instance = new Singleton (); //... private Singleton (){ //... } public static Singleton getInstanece(){ return instance; }}//4、饿汉式 变种public class Singleton{ private static Singleton instance = null; static{ instance = new Singleton (); } //... private Singleton (){ //... } public static Singleton getInstance(){ return instance; }}//5、静态内部类 也是在classloder机制下保证只有一个实例被创建public class Singleton{ private static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton (); } //... private Singleton(){ //... } public static final Singleton getInstance(){ return SingletonHolder.INSTANCE; }}//6、枚举public class Singleton{ //... public enum Singleton { INSTANCE; public void whateverMethod() { } } }//7、双重校验 上文已述
阅读全文
0 0
- 双重校验锁:Java并发编程中的陷阱
- 双重校验锁 -- Java并发编程中的陷阱
- Java多线程并发中的双重检查锁定与延迟初始化
- Java带有双重校验锁的单例模式
- Java多线程编程-(3)-从一个错误的双重校验锁代码谈一下volatile关键字
- java中的并发编程 (1)
- java并发编程中的随笔
- 单例模式--双重校验锁
- 单例模式 双重校验锁
- Java并发编程:volatile关键字解析 和双重检查(Double-Check)
- Java并发编程实战--双重检查加锁( double check lock)与延迟初始化占位
- Java设计模式——单例模式(双重校验锁)
- 【Java】Java并发编程中的锁(一)
- Java并发编程的艺术-Java中的锁
- Java并发编程艺术 5 Java中的锁
- java双重检测锁
- Java并发编程-锁
- 也来说说Java中的锁--并发编程关键知识点
- Spring中@Autowired注解、@Resource注解的区别
- android studio 提示IDE出现错误,或输入代码没有提示
- 17年双十一写的一堆废话
- POJ 1741 Tree(树分治+容斥原理+树的重心)
- LeetCode:Maximum Subarray
- 双重校验锁 -- Java并发编程中的陷阱
- Banner轮播模版
- 身份证之js获取性别 年龄 出生日期
- Python装饰器学习
- vue init 报错
- ubuntu安装eclipse
- ARM内核和架构理解
- j2ee的web项目的定时器,不用受到拦截器的拦截,因为根本不是http url请求
- mysql延时复制