单列模式-双重锁校验解析
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
这里第一个if,第二个if,synchronized 的本质都是为了避免产生多实例,但侧重点个不相同。
第一个if判断很好理解,即如果成员变量singleton已经被实例化了,当然不需要重复创建了,直接返回该成员变量即可。
使用synchronized的目的是保证在多线程环境中,同一时间只有一个线程执行new操作。同时synchronized也可以保证线程可见性,即当当前线程实例化对象之后,其他线程获取锁之后能够感知到上一个线程创建的对象,从而避免重复创建。假设A,B两个线程同时执行 getSingleton() 操作,B线程先获取锁,A线程阻塞。当B线程执行new操作,创建完对象后,释放锁时会立即将 singleton的值刷新回主内存,当A线程拿到锁时,A线程会从主内存中获取最新的的singleton值,此时singleton已经有值了,该值即为B线程创建的对象的地址,所以A线程在执行第二个if判断时恒为false,不会执行new操作。
第二个if判断是为了保证在多线程环境中,对象只被new一次,即假如已经有线程创建了对象,则当前线程无需再执行new操作。
volatile既可以保证线程可见性,也可以防止指令重排序。这里synchronized已经保证了线程可见性,所以这里的volatile主要用来防止指令重排序,因为new操作,赋值操作,return操作不是原子操作,它们执行的顺序可能是乱序的,所以要使用volatile。
附带一张volatile的原理图