面试常考设计模式

单例模式 4

懒汉(线程不安全)

1
2
3
4
5
6
7
8
9
10
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {};
public static Singleton getUniqueInstance() {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}

如果有多个线程能进入 if(uniqueInstance == null) 并且此时 uniqueInstance 为空,就会实例化多个Single

双重校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton {
private static volatile Singleton uniqueInstance;
private Singleton() {};
public static Singleton getInstance() {
if(uniqueInstance == null) {
synchronized(Singleton.class) {
if(uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}

之所以要进行两次 if 判断,是因为如果两个线程同时执行 if 语句,两个线程都会进入 sychronized 语句块,等到第一个线程完成实例化之后第二个线程也会进入。为了避免第二次实例化,第二个线程如果判断得到uniqueInstance不为空,就不会进行实例化了,保证了只有一个实例

volatile 可以禁止指令重排,因为 uniqueInstance = new Singleton(); 这段代码实际是分3步执行的:

  1. 为 uniqueInstance 分配内存空间
  2. 初始化uniqueInstance
  3. 将uniqueInstance指向被分配的内存地址

由于JVM的执行重排特性,这段代码可能是按照1-3-2的顺序执行的,如果T1线程执行了1和3,T2线程调用getInstance发现不为空,就返回了 uniqueInstance ,但此时uniqueInstance还未被初始化

工厂模式 2

观察者模式 1