最近在学习Eurake源码(版本为1.7.2),看到源码里面有关于单例模式的,特地记录学习一波。
这个代码是在com.netflix.config.ConfigurationManager类里面,下面是部分代码:
static volatile AbstractConfiguration instance = null;
public static AbstractConfiguration getConfigInstance() {
if (instance == null) {
synchronized (ConfigurationManager.class) {
if (instance == null) {
instance = getConfigInstance(Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG));
}
}
}
return instance;
}
直接调用ConfigurationManager.getConfigInstance()方法获取AbstractConfiguration对象,下面分析下单例模式(双重锁+volatile)
场景是并发情况下,多个线程同时执行到ConfigurationManager.getConfigInstance()方法,可以看到这个方法上面是没有synchronized关键字.
1.发线程都会进入方法内部,此时脑海中会冒出一副脑图:
2.假设线程1先拿到锁,判断instance == null,判断结果为true,执行
instance = getConfigInstance(Boolean.getBoolean(DynamicPropertyFactory.DISABLE_DEFAULT_CONFIG));
方法,此时instance已经被初始化了,此时没有加volatile修饰的内存脑图如下:
假如此时没有instance 引用前面没有volatile修饰,只会在线程1内部完成初始化,对于线程2来说,instance还是=null,线程2还是存在一定的概率把instance在一次初始化一遍。
以上纯属幻想,我们这里instance引用前面是有volatile修饰的,加了volatile修饰实际脑图为:
volatile关键字的作用得看自己实力领悟了,其中一个作用就是会把其装饰的引用对象立即刷回主内存,并且将其他线程引用(线程2)置为无效。当线程2获取到锁,这个时候判断instance已经不等于null了,判断结果为false,所以不会进行下一步的初始化了。进而达到单例的控制。
最后的最后,加油,加油,加油!!!