多线程情况下双重检查锁定问题的分析与优化
来源:互联网 发布:工时记录软件 编辑:程序博客网 时间:2024/06/06 06:30
- 双重检查锁定(Double-Checked Locking)的由来
Java程序中,有时候需要推迟一些高开销对象的初始化操作,等到使用的时候才进行对象初始化。双重检查锁定是一种常见的延迟初始化技术。但是在多线程情况下,使用不当很容易出现问题。下面就来分析一下非线程安全的一段代码:
public class DoubleCheckedLocking {private static Instance instance;public static Instance getInstance() {if (instance == null) {// line A 第一次检查synchronized (DoubleCheckedLocking.class) {// line B 加锁if (instance == null) {// line C 第二次检查instance = new Instance();// line D 创建一个对象。 问题就出在这里!!!}}}return instance;}}从代码来看,如果第一次检查instance不为null,则不用继续执行加锁和初始化操作,可以降低synchronized带来的性能开销。但是如果在多线程情况下一个线程执行第一次检查的时读取的instance不为null,然而此时instance引用的对象在另外一个线程中还没有初始化完成,这时程序就会出现错误。
2. 问题的根源
可以将上述创建对象的代码进一步分解为下面3行伪代码:
memory = allocate();//step1. 为对象分配内存空间createInstance(memory);//step2. 对象的初始化instance = memory;//step3. 设置instance指向分配的内存地址上面三行代码在执行的时候可能会发生制定重排序。step2和step3重排序之后执行顺序如下:
memory = allocate();//step1. 为对象分配内存空间instance = memory;//step3. 设置instance指向分配的内存地址 此处的对象还没有被初始化,正是问题的所在!!!createInstance(memory);//step2. 对象的初始化
在多线程条件下,如果线程A使用第二种指令排序方式来初始化instance对象,当程序执行到step3的时候,若线程B在执行第一次检查,将会获得一个还未初始化的对象,此时线程B就会出现问题。3. 解决方案
发现问题的根源以后,可以有两个办法来解决。
- 不允许step2和step3进行指令重排序。
- 允许step2和step3进行重排序,但是不允许其他线程“看到”此重排序。
3.1. 基于volatile的解决方案
可以对前面DoubleCheckedLocking方法稍作修改(把instance声明为volatile类型,声明为volatile类型后,代码重排序将被禁止),即可实现线程安全的延迟初始化。
public class DoubleCheckedLocking {private volatile static Instance instance;public static Instance getInstance() {if (instance == null) {synchronized (DoubleCheckedLocking.class) {if (instance == null) {instance = new Instance();}}}return instance;}}
3.2. 基于类初始化的解决方案
JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。
public class InstanceFactory {private static class InstanceHolder {public static Instance instance = new Instance();}public static Instance getInstance(){return InstanceHolder.instance;}}
阅读全文
0 0
- 多线程情况下双重检查锁定问题的分析与优化
- Java多线程并发中的双重检查锁定与延迟初始化
- 多线程下双重检查锁的问题及解决方法
- 多线程下双重检查锁的问题及解决方法
- 单例模式中的 双重检查锁定(Double-Check Locking ) (多线程下单例模式中的双重检查锁定的实现)
- 并发编程的艺术-双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与单例模式
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- 双重检查锁定与延迟初始化
- Android Service两种启动方式详解(总结版)
- SQL慢查询在Greenplum/Deepgreen中的定位方法
- Oracle的空值处理函数
- CentOS7安装Apache与PHP与新的防火墙配置
- es迁移分片,重置主节点。
- 多线程情况下双重检查锁定问题的分析与优化
- J2SE基础
- github 出现 Permission denied (publickey)的解决
- 函数定义及调用
- 基于安装包方式部署mesos集群
- 个人总结1
- 李宏毅机器学习课程1~~~Introduction &Regression
- WordPress统计当前页面数据库查询次数及消耗时间的方法
- TinyHttpSever