1.在看源码之前,首先先解释一下什么是double check,以及单例模式中为什么需要double check来进行单例模式的创建?
double check,也叫双重检测,主要利用两次的判断进行校验当前单例的创建情况。
如下面的代码
static volatile AbstractConfiguration instance = null;
public static AbstractConfiguration getConfigInstance() {
if (instance == null) {
Class var0 = ConfigurationManager.class;
synchronized(ConfigurationManager.class) {
if (instance == null) {
instance = getConfigInstance(Boolean.getBoolean("archaius.dynamicProperty.disableDefaultConfig"));
}
}
}
return instance;
}
- 首先第一层是instance == null , 他主要的作用是减少synchornized锁竞争的压力,避免在大量线程访问的情况下,导致锁升级为重量级锁,从而导致线程之间互斥而进行长时间堵塞,严重的甚至可能导致OOM的情况。所以加第一层可以有效的阻挡部分已经获取单例的线程再次进入,减少线程间锁的竞争压力。
- 第二层: 主要是保证在获取锁后的线程确保实例是空的情况下在进行创建,保证了单例仅创建了一次。
如上情况,看似已经比较的完美了,但是还有会有问题,问题就出现在多线程调用的时候,由于单例创建的实例存在于公共内存中,当实例创建之后,其他正在创建的实例不一定立马就知道单例的变化,所以还需要一个修饰符Volitile,它不仅仅可以阻止执行过程中指令的重排序,还可以保证线程之间的可见性(通过MESI缓存一致性协议确定),让创建的实例保证有且仅有一个。
2.详细看看这个在Eureka源码中是如何使用的。
还是寻找入口点从EurekaBootstrap启动类入口。
public class EurekaBootStrap implements ServletContextListener {
public void contextInitialized(ServletContextEvent event) {
try {
//进行环境初始化
this.initEurekaEnvironment();
this.initEurekaServerContext();
ServletContext sc = event.getServletContext();
sc.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
} catch (Throwable var3) {
logger.error("Cannot bootstrap eureka server :", var3);
throw new RuntimeException("Cannot bootstrap eureka server :", var3);
}
}
}
紧接跟入如下代码:
protected void initEurekaEnvironment() throws Exception {
logger.info("Setting the eureka configuration..");
String dataCenter = ConfigurationManager.getConfigInstance().getString("eureka.datacenter");
if (dataCenter == null) {
logger.info("Eureka data center value eureka.datacenter is not set, defaulting to default");
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.datacenter", "default");
} else {
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.datacenter", dataCenter);
}
String environment = ConfigurationManager.getConfigInstance().getString("eureka.environment");
if (environment == null) {
ConfigurationManager.getConfigInstance().setProperty("archaius.deployment.environment", "test");
logger.info("Eureka environment value eureka.environment is not set, defaulting to test");
}
}
重点为如下语句:
String dataCenter = ConfigurationManager.getConfigInstance().getString("eureka.datacenter");
继续跟入:
public static AbstractConfiguration getConfigInstance() {
if (instance == null) {
Class var0 = ConfigurationManager.class;
synchronized(ConfigurationManager.class) {
if (instance == null) {
instance = getConfigInstance(Boolean.getBoolean("archaius.dynamicProperty.disableDefaultConfig"));
}
}
}
return instance;
}
这里就应用了如开始的double check 的代码 。整体的应用流程就是这样,全局创建一个配置实例。
总结
总体的流程图如下所示,需要的朋友可以下载研究保存。