说说双重检查加锁单例模式为什么两次判断?

今天面试被问到这道题没说出来,复盘一下

先上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class Singleton {

private static volatile Singleton singleton = null;

private Singleton() {
}

public static Singleton getInstance(){
//第一次校验singleton是否为空
if(singleton==null){
synchronized (Singleton.class){
//第二次校验singleton是否为空
if(singleton==null){
singleton = new Singleton();
}
}
}
return singleton;
}


public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName()+" : "+Singleton.getInstance().hashCode());
}
}).start();
}
}
}

为什么是双重校验锁实现单例模式呢?

  1. 第一次校验: 也就是第一个 if(singleton==null),由于单例模式只要一次创建实例即可,所以当创建了一个实例之后,再次调用 getInstance 方法就不必要进入同步代码块,不用竞争锁。直接返回前面创建的实例即可。

  2. 第二次校验:第个校验是防止二次创建实例,假如有一种情况,当 singleton 还未被创建时,线程 t1 调用 getInstance 方法,由于第一次判断 singleton==null,此时线程 t1 准备继续执行,但是由于资源被线程 t2 抢占了,此时 t2 页调用 getInstance 方法。

    ​ 同样的,由于 singleton 并没有实例化,t2 同样可以通过第一个 if,然后继续往下执行,同步代码块,第二个 if 也通过,然后 t2 线程创建了一个实例 singleton。

    ​ 此时 t2 线程完成任务,资源又回到 t1 线程,t1 此时也进入同步代码块,如果没有这个第二个 if,那么,t1 就也会创建一个 singleton 实例,那么,就会出现创建多个实例的情况,但是加上第二个 if,就可以完全避免这个多线程导致多次创建实例的问题。

Others:

  • 感觉面试还是紧张了,稍微想一下其实就明白了;
-------------本文结束感谢您的阅读-------------