Java并发(七):双重检验锁定DCL
双重检查锁定(Double Check Lock,DCL)
1、懒汉式单例模式,无法保证线程安全:
- public class Singleton {
- private static Singleton singleton;
- private Singleton() {
- }
- public static Singleton getInstance() {
- if (singleton == null) {// 多个线程同时执行到此,会生成多个Singleton实例
- singleton = new Singleton();
- }
- return singleton;
- }
- }
2、同步处理,synchronized就会导致这个方法比较低效:
- public class Singleton {
- private static Singleton singleton;
- private Singleton() {}
- public static synchronized Singleton getInstance() {
- if (singleton == null) {
- singleton = new Singleton();
- }
- return singleton;
- }
- }
3、双重检查 DCL:
- public class Singleton {
- private static Singleton singleton;
- Integer a;
- private Singleton(){}
- public static Singleton getInstance(){
- if(singleton == null){ // 1 只有singleton==null时才加锁,性能好
- synchronized (Singleton.class){ //
- if(singleton == null){ //
- singleton = new Singleton(); //
- }
- }
- }
- return singleton;
- }
- }
但是,仍然有问题!!
创建对象过程:
(1)分配内存空间
(2)初始化对象
(3)将内存空间的地址赋值给对应的引用
(2)(3)会被处理器优化,发生重排序
举例:
A线程singleton = new Singleton()发生重排序,将分配的内存空间引用赋值给了静态属性singleton(即singleton != null),而对象还未初始化(即Integer a == null);
B线程此时调用getInstance()方法,因为singleton != null,直接返回singleton。当B线程使用singleton的a属性时就会空指针。
分析:
问题在于singleton = new Singleton()的重排序
(1)不允许初始化阶段步骤2 、3发生重排序。
(2)允许初始化阶段步骤2 、3发生重排序,但是不允许其他线程“看到”这个重排序。
解决:
1、利用volatile限制重排序
- public class Singleton {
- private volatile static Singleton singleton;// 通过volatile关键字来确保安全
- private Singleton(){}
- public static Singleton getInstance(){
- if(singleton == null){
- synchronized (Singleton.class){
- if(singleton == null){
- singleton = new Singleton();
- }
- }
- }
- return singleton;
- }
- }
(1)分配内存空间
(2)初始化对象
(3)将内存空间的地址赋值给对应的引用
第(3)步 volatile修饰的变量singleton的写入操作,通过内存屏障限制的重排序 参考:Java并发(六):volatile的实现原理
2、利用类初始化
JVM会保证一个类的类构造器在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器,其他线程都需要阻塞等待,直到活动线程执行方法完毕。
特别需要注意的是,在这种情形下,其他线程虽然会被阻塞,但如果执行初始化的那条线程退出后,其他线程在唤醒之后不会再次进入/执行初始化,因为在同一个类加载器下,一个类型只会被初始化一次。
- public class Singleton {
- private static class SingletonHolder{
- public static Singleton singleton = new Singleton();
- }
- public static Singleton getInstance(){
- return SingletonHolder.singleton;
- }
- }
参考资料:
【死磕Java并发】—–Java内存模型之从JMM角度分析DCL
Java并发(七):双重检验锁定DCL的更多相关文章
- Java盲点:双重检查锁定及单例模式
尊重原创: http://gstarwd.iteye.com/blog/692937 2004 年 5 月 01 日 所有的编程语言都有一些共用的习语.了解和使用一些习语很有用,程序员们花费宝贵的时间 ...
- JAVA并发七(多线程环境中安全使用集合API)
在集合API中,最初设计的Vector和Hashtable是多线程安全的.例如:对于Vector来说,用来添加和删除元素的方法是同步的.如果只有一个线程与Vector的实例交互,那么,要求获取和释放对 ...
- java 并发(七)--- ThreadLocal
文章部分图片来自参考资料 问题 : ThreadLocal 底层原理 ThreadLocal 需要注意什么问题,造成问题的原因是什么,防护措施是什么 ThreadLocal 概述 Threa ...
- Java并发--三大性质
一.多线程的三大性质 原子性:可见性.有序性 二.原子性 原子性介绍 原子性是指:一个操作时不可能中断的,要么全部执行成功要么全部执行失败,有着同生共死的感觉.即使在多线程一起执行的时候,一个操作一旦 ...
- java并发编程系列七:volatile和sinchronized底层实现原理
一.线程安全 1. 怎样让多线程下的类安全起来 无状态.加锁.让类不可变.栈封闭.安全的发布对象 2. 死锁 2.1 死锁概念及解决死锁的原则 一定发生在多个线程争夺多个资源里的情况下,发生的原因是 ...
- DCL,即Double Check Lock,中卫双重检查锁定。
DCL,即Double Check Lock,中卫双重检查锁定. [Java并发编程]之十六:深入Java内存模型——happen-before规则及其对DCL的分析(含代码) 关于单例.关于DCL: ...
- java中的双重锁定检查(Double Check Lock)
原文:http://www.infoq.com/cn/articles/double-checked-locking-with-delay-initialization#theCommentsSect ...
- Java并发——DCL问题
转自:http://www.iteye.com/topic/875420 如果你搜索网上分析dcl为什么在java中失效的原因,都会谈到编译器会做优化云云,我相信大家看到这个一定会觉得很沮丧.很无助, ...
- JAVA 双重检查锁定和延迟初始化
双重检查锁定的由来在Java程序中,有时需要推迟一些高开销的对象的初始化操作,并且只有在真正使用到这个对象的时候,才进行初始化,此时,就需要延迟初始化技术.延迟初始化的正确实现是需要一些技巧的,否则容 ...
随机推荐
- Fiddler 抓包工具总结(转)
阅读目录 1. Fiddler 抓包简介 1). 字段说明 2). Statistics 请求的性能数据分析 3). Inspectors 查看数据内容 4). AutoResponder 允许拦截制 ...
- 【Explain】mysql之explain详解(分析索引的最佳使用)
在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain 这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句 ...
- nginx配置不当导致的目录遍历下载漏洞-“百度杯”CTF比赛 2017 二月场
题目:http://98fe42cede6c4f1c9ec3f55c0f542d06b680d580b5bf41d4.game.ichunqiu.com/login.php 题目内容: 网站要上线了, ...
- Linux下帮助命令
帮助命令(各种命令区别) 最常用的帮助命令 help --help help cd 查看内置命令的使用 info man help cd 查看内置命令的使用 获得帮助的途径: ma ...
- powerpc平台移植zebra或quagga-0.99.23
1,先configure ./configure --enable-vtysh --disable-bgpd --disable-ripd --disable-ripngd --disable- ...
- 很多人都没用过的轻量级Oracle数据库数据导出工具SQLLDR2——性能超赞
SQLLDR2 介绍 每周发表一篇数据库或大数据相关的帖子,敬请关注 1. 工具介绍 Sqluldr2(SQL * UnLoader 第二版)是灵活与强大的 Oracle 文本导出程序,已被大众使 用 ...
- mysql 创建,授权,删除 用户
1.创建用户 创建一个用户名是 lefunyun 密码是 X5A4FU8I0lKM21YPYUzP 账号 CREATE USER lefuyun@localhost IDENTIFIED BY 'X5 ...
- 洛谷 P1202 [USACO1.1]黑色星期五Friday the Thirteenth 题解
题目传送门 这道题暴力就能解决. #include<bits/stdc++.h> using namespace std; int xi; ,ans[]; int main() { int ...
- MVC – 8.Razor 布局
8.1.@RenderBody() 8.2.多个"占位符":@RenderSection() 8.3.js合并 @Scripts.Render("~/bundles/js ...
- spring-cloud-sleuth+zipkin追踪服务实现(二)
1. 简述 在上一节<spring-cloud-sleuth+zipkin追踪服务实现(一)>中,我们使用microservice-zipkin-server.microservice-z ...