双重检查锁定在延迟初始化的单例模式中见得比较多(单例模式实现方式很多,这里为说明双重检查锁定问题,只选取这一种方式),先来看一个版本:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
|
上面是最原始的模式,一眼就可以看出,在多线程环境下,可能会产生多个Singleton实例,于是有了其同步的版本:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public synchronized static Singleton
getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
|
在这个版本中,每次调用getInstance都需要取得Singleton.class上的锁,然而该锁只是在开始构建Singleton 对象的时候才是必要的,后续的多线程访问,效率会降低,于是有了接下来的版本:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
|
很好的想法!不幸的是,该方案也未能解决问题之根本:
原因在于:初始化Singleton 和 将对象地址写到instance字段 的顺序是不确定的。在某个线程new Singleton()时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化;此时若另外一个线程来调用getInstance,取到的就是状态不正确的对象。
鉴于以上原因,有人可能提出下列解决方案:
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
Singleton temp;
synchronized(Singleton.class) {
temp = instance;
if(temp == null) {
synchronized(Singleton.class) {
temp = new Singleton();
}
instance = temp;
}
}
}
return instance;
}
}
|
该方案将Singleton对象的构造置于最里面的同步块,这种思想是在退出该同步块时设置一个内存屏障,以阻止初始化Singleton 和 将对象地址写到instance字段 的重新排序。
不幸的是,这种想法也是错误的,同步的规则不是这样的。退出监视器(退出同步)的规则是:所以在退出监视器前面的动作都必须在释放监视器之前完成。然而,并没有规定说退出监视器之后的动作不能放到退出监视器之前完成。也就是说同步块里的代码必须在退出同步时完成,而同步块后面的代码则可以被编译器或运行时环境移到同步块中执行。
编译器可以合法的,也是合理的,将instance = temp移动到最里层的同步块内,这样就出现了上个版本同样的问题。
在JDK1.5及其后续版本中,扩充了volatile语义,系统将不允许对 写入一个volatile变量的操作与其之前的任何读写操作 重新排序,也不允许将 读取一个volatile变量的操作与其之后的任何读写操作 重新排序。
在jdk1.5及其后的版本中,可以将instance 设置成volatile以让双重检查锁定生效,如下:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
synchronized(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
|
需要注意的是:在JDK1.4以及之前的版本中,该方式仍然有问题。
分享到:
相关推荐
在介绍双检锁模式(Double-Checked Locking Pattern,DCLP)的C++实现中,Scott Meyers和Andrei Alexandrescu在其2004年的文章中指出,传统的单例模式实现并不具备线程安全性。单例模式是设计模式中经常被提及的一种...
《C++ and the Perils of Double Checked Locking》是一篇探讨C++编程中双重检查锁定(Double-Checked Locking)模式潜在问题的文献。在多线程编程中,双重检查锁定是一种常见的优化策略,旨在减少对同步原语的依赖...
标题:C++与双检查锁定(Double Checked Locking)的陷阱 描述:C++如何解决单例模式的线程安全问题 ### 关键知识点解析: #### 单例模式的线程安全挑战 单例模式是一种设计模式,确保一个类只有一个实例,并提供...
在Java高级面试中,面试官通常会关注候选人在核心Java、多线程、集合框架、JVM内存管理、设计模式、数据库操作、...以上内容是Java高级面试中可能涉及的关键知识点,深入理解和掌握这些知识将有助于在面试中表现出色。
Qt5学习笔记——QRadioButton与QButtonGroup Qt5学习笔记——QRadioButton与QButtonGroup是Qt5中两个重要的控件,用于实现单选按钮的功能。本文将详细介绍QRadioButton和QButtonGroup的使用方法和属性。 一、...
本文深入探讨了AngularJS框架中的ng-checked指令,通过真实案例代码的形式展示了如何使用ng-checked实现复选框的状态记忆与回写。ng-checked指令在AngularJS中用于获取和设置复选框(checkbox)的选中状态。它依赖于...
在Web开发中,AngularJS作为前端框架被广泛使用,它提供了一套完整的...虽然在不同的场景下可能需要配合其他AngularJS指令和数据绑定来共同实现复杂的功能,ng-checked仍然作为基础指令被频繁应用于各种动态交互中。
在Java并发编程中,双检锁(Double-Checked Locking)是一种用于减少同步开销的优化技术,尤其适用于懒加载(lazy initialization)的场景。本文将详细探讨双检锁的工作原理、潜在问题以及如何安全地实现它。 双检锁...
双重检查锁(Double-Checked Locking, DCL)是一种在多线程环境中用于实现懒加载(lazy loading)的设计模式。它通过两次检查来确定是否需要获取锁,从而避免不必要的同步操作,提高程序性能。然而,DCL的实现并不像表面...
DCL(Double-checked locking)是Java双重检查加锁单例模式的一种实现方法。它使用了synchronized关键字来确保线程安全,但是这也会带来性能损失。DCL看起来是一个聪明的优化,但是它却不能保证正常工作。 在多线程...
在这个问题中,开发者遇到了一个关于`default-checked-keys`属性的问题,即当尝试将该属性设置为空数组时,树形控件的节点依然保持选中的状态,这与预期的行为不符。 `default-checked-keys`属性是Element UI Tree...
在Java中,有多种实现单例模式的方法,包括简单实现、双重检查锁定(Double-Checked Locking)、静态内部类和枚举类。下面我们将详细探讨这些不同的实现方式。 1. **简单实现(非线程安全)** 最简单的单例实现...
为了解决性能问题,引入了"双重检查锁定"(Double-Checked Locking)策略: ```java public class DoubleCheckedLocking { private volatile static Instance instance; public static Instance getInstance() { ...
视频可能详细讲述了如何在Java中实现单例的第二种方式,这通常涉及到懒汉式(Lazy Initialization)的双重检查锁定(Double-Checked Locking)。 在Java中,单例模式的实现通常有两种主要方法: 1. 饿汉式(Eager ...
Software Adaptation in an Open Environment: A Software Architecture Perspective by Yu Zhou ...The organization and presentation of the book will be double-checked by professional scholars
在上篇文章给大家介绍了js操作表单实例讲解(下)的相关...———————————————- checked 返回或设置单选的选中状态 true 选中 false 未选中 value 属性 获取选中的值,必须先判断选中状态 ———————
北京火龙果软件工程技术中心意图无论什么时候当临界区中的代码仅仅需要加锁一次,同时当其获取锁的时候必须是线程安全的,可以用DoubleCheckedLocking模式来减少竞争和加锁载荷。动机1、标准的单例。开发正确的有效...
- 异常处理:理解Checked异常和Unchecked异常的区别,以及如何有效地使用try-catch-finally语句。 - 内存管理:了解堆内存和栈内存的区别,以及对象的生命周期。 2. **并发处理**: - 线程:创建线程的多种方式...
这里,`checked--effect-name`需要替换为23种动画效果中的一个,如`checked--pulse`或`checked--rotate`。 3. **自定义样式**:除了预设的动画效果,你还可以通过CSS对复选框和单选按钮的样式进行个性化调整,以...