dubbo源码中多处用到双重检查锁,
比如ExtensionLoader#getExtensionClasses
以上源码中,cachedClasses为多个线程共享资源。比如多个线程调用getExtensionClasses()方法的时候,假设X,Y线程都判断第558行classes==null,都进入了559行。
接着X线程抢先拿到锁,从cachedClasses获取值,发现为空,为其赋值,X线程做完任务后,释放锁。
接着Y线程也抢到锁,从cachedClasses获取值,发现不为空,释放锁。(如果少了561行的判断,则Y线程将再一次的进行赋值)。
以下给出个单个检查锁的单例模式
package com.shopping.pattern.singleton.doublelock;
import java.util.concurrent.CountDownLatch;
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
public static void main(String[] args) {
final int threadNum=50;
//发令枪,起到倒计时器的作用。cdl.await会让所有线程等待,只有当计数减到为0时,
//所有线程并发执行。
final CountDownLatch cdl=new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
//cdl.await会让所有线程等待,只有当计数减到为0时,所有线程并发执行。
cdl.await();
System.out.println(Singleton.getSingleton());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//计数减一
cdl.countDown();
}
}
}
运行测试截图:出现了两个实例。
getSingleton代码调整后,只能获取单个实例
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if(instance==null){
instance = new Singleton();
}
}
}
return instance;
}