双重校验锁:即在代码 synchronized 代码块之前和代码块开始,都对一个变量进行校验
javax.xml.parsers.FactoryFinder 类里面有个方法 static
1 | try { |
其中 firstTime 和 cachePros 为。firstTime 判断是否已经缓存过,cachePros 缓存 properties1
2
3
4
5
6
7
8
9
10/**
* Flag indicating if properties from java.home/lib/jaxp.properties
* have been cached.
*/
static volatile boolean firstTime = true;
/**
* Cache for properties in java.home/lib/jaxp.properties
*/
private static final Properties cacheProps = new Properties();
那么,问题来了,为什么要写成这么蛋疼的加锁形式呢?
不加锁的情况
1 | try { |
当有多个线程调用这一段时,有种情况会出现问题,cachePros 已经缓存了,但是另外一个线程执行到了 if(firstTime),此时 firstTime 还是为 true。那么就出现问题了
加锁的情况
1 | try { |
这种情况效率会比较低一点,因为同一时间只允许一个线程执行这段代码。但是可以在前面添加一个判断,让程序只在第一次调用时阻塞
1 | try { |
使用 volatile 同步变量并防止指令重排
jvm 优化指令时,有可能会重排指令,虽然感觉这里不需要防止指令重排。啊哈哈哈