Why double checking locks singleton to use the volatile keyword?

Foreword

From the Java memory model, combined with atoms of concurrent programming, visibility, ordering three point of view of the role of volatile and compiled from the perspective of a volatile principle roughly speaking, describes the application scenarios that keyword; that analysis under volatile issue is how to avoid double-check the lock appears in the singleton pattern in this supplement.

Concurrent programming of three conditions

1, Atomic: atomicity way to achieve more, available synchronized, lock to lock, AtomicInteger, etc., but the volatile keyword can not guarantee atomicity;
2. Visibility: To achieve visibility, can also be synchronized, lock, volatile keyword used to ensure visibility;
3, orderly: to avoid reordering command, synchronized, lock function block execution order is natural, volatile keyword effectively prohibit instruction reordering, the program execution to achieve orderliness;

Double-checked locking

Double-checked locking (Double check locked) mode often occur in some of the framework source code, the purpose is to initialize a variable delay. This mode can also be used to create a single embodiment. Let's look at an example of the double-checked locking of Spring.
Why double checking locks singleton to use the volatile keyword?

This case you need to load the configuration file to handlerMappings, because reading the resource is time-consuming, so the action into real time of need handlerMappings. We can see in front of handlerMappings use volatile. Ever wonder why some need volatile? Although previous understanding of the principle of double-checked locking, but it ignores the variables used volatile.
Here we look at the reasons behind this.

Lazy Initialization error example

Initialize a variable delay conceivable, the most simple example is taken for determination variable.
Why double checking locks singleton to use the volatile keyword?

这个例子在单线程环境可以正常运行,但是在多线程环境就有可能会抛出空指针异常。为了防止这种情况,我们需要在该方法上使用 synchronized。这样该方法在多线程环境就是安全的,但是这么做就会导致每次方法调用都需要获取与释放锁,开销很大。
深入分析可以得知只有在初始化的变量的需要真正加锁,一旦初始化之后,直接返回对象即可。
所以我们可以将该方法改造以下的样子。
Why double checking locks singleton to use the volatile keyword?

这个方法首先判断变量是否被初始化,没有被初始化,再去获取锁。获取锁之后,再次判断变量是否被初始化。第二次判断目的在于有可能其他线程获取过锁,已经初始化改变量。第二次检查还未通过,才会真正初始化变量。
这个方法检查判定两次,并使用锁,所以形象称为双重检查锁定模式。
这个方案缩小锁的范围,减少锁的开销,看起来很完美。然而这个方案有一些问题却很容易被忽略。

new 实例背后的指令

这个被忽略的问题在于 Cache cache=new Cache()这行代码并不是一个原子指令。使用 javap -c指令,可以快速查看字节码。
Why double checking locks singleton to use the volatile keyword?

从字节码可以看到创建一个对象实例,可以分为三步:
分配对象内存
调用构造器方法,执行初始化
将对象引用赋值给变量。
虚拟机实际运行时,以上指令可能发生重排序。以上代码 2,3 可能发生重排序,但是并不会重排序 1 的顺序。也就是说 1 这个指令都需要先执行,因为 2,3 指令需要依托 1 指令执行结果。
Java 语言规规定了线程执行程序时需要遵守 intra-thread semantics。intra-thread semantics 保证重排序不会改变单线程内的程序执行结果。这个重排序在没有改变单线程程序的执行结果的前提下,可以提高程序的执行性能。
虽然重排序并不影响单线程内的执行结果,但是在多线程的环境就带来一些问题。
Why double checking locks singleton to use the volatile keyword?

上面错误双重检查锁定的示例代码中,如果线程 1 获取到锁进入创建对象实例,这个时候发生了指令重排序。当线程1 执行到 t3 时刻,线程 2 刚好进入,由于此时对象已经不为 Null,所以线程 2 可以自由访问该对象。然后该对象还未初始化,所以线程 2 访问时将会发生异常。

volatile 作用

正确的双重检查锁定模式需要需要使用 volatile。volatile主要包含两个功能。
保证可见性。使用 volatile定义的变量,将会保证对所有线程的可见性。
禁止指令重排序优化。
由于 volatile禁止对象创建时指令之间重排序,所以其他线程不会访问到一个未初始化的对象,从而保证安全性。
注意,volatile禁止指令重排序在 JDK 5 之后才被修复

使用局部变量优化性能

重新查看 Spring 中双重检查锁定代码。
Why double checking locks singleton to use the volatile keyword?

The method can see the internal local variable, the first value is assigned to the instance variable local variable, then judge. Finally, write the contents of the first local variable, and then assign a local variable to the instance variables.
Local variables are not used with respect to a local variable, the performance can be improved. Mainly due to the volatile variables you need to create an object prohibit instruction reordering, which requires some additional action.

to sum up

Creating an object instruction reordering may occur, may prohibit the use of volatile reordering of instructions, to ensure system security in a multithreaded environment.

At last

Welcome to share with everyone, like the point of a praise yo remember the article, thanks for the support!

Guess you like

Origin blog.51cto.com/14442094/2429906