类文件位置:
org.apache.dubbo.common.extension.ExtensionLoader
代码片段
...
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
...
//写法1
private Holder<Object> getOrCreateHolder(String name) {
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<>()); //1
holder = cachedInstances.get(name); //2
}
return holder;
}
首先这段代码要实现的功能其实很简单,判断holder是否为空,若不为空,则返回;若为空,则创建新的holder。
请注意看编号为1和2的两行代码。
初次看到这段代码时,很是奇怪,判断holder为null之后,为什么不将new出来的Holder对象直接赋值给holder,而是先put之后再get,就是说,为什么不是下面这种写法:
//写法2
private Holder<Object> getOrCreateHolder(String name) {
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
holder = new Holder<>(); //3
cachedInstances.putIfAbsent(name, holder); //4
}
return holder;
}
但随后我想明白了。在写法2中,当两个线程同时判断了holder==null之后,他们会分别创建出两个Holder对象,但是ConcurrentHashMap的putIfAbsent方法,决定只有一个线程put成功,这会导致另一个线程所持有的holder和map中存储的holder不是同一个对象,这就导致了线程安全问题。
再看官方写法,也就是写法1,在put之后,再进行get一次,就没有线程安全的问题了。