单例模型的双重检查机制

单例模式:在内存中只能有一个实例,只能new一个对象。

  • 首先我们先来看一个简单的例子:
    单例模型的双重检查机制
    上图单例代码中可能new的过程很耗时间和空间,可不可以使用它的时候再new。

  • 下图代码解决了上面的问题:

单例模型的双重检查机制
但是上图代码如果在多线程访问它时,会得到不一样的结果,如果第一个线程来了,判断它不为空,第一个线程停止,第二个线程也来了,判断依然不为空,这时第一个线程恢复运行,这时两个线程都new这个对象,所以最后会new出不同的对象。

  • 下图代码解决了上述问题。
    单例模型的双重检查机制
    但是这时锁太粗,会把这个方法里不需要加锁的业务逻辑也加锁。
  • 调整synchronized的位置
    单例模型的双重检查机制
    如果Instance为空的时候再上锁。但是如果第一个线程来了,判断它不为空,第一个线程停止,第二个线程也来了,判断依然不为空,拿到锁,new了一个对象,释放锁。这时第一个线程恢复运行,锁的状态为空,也可以拿到锁,new对象。因此依然做不到线程安全,因为判断和new没有在同一个临界区里,没有被锁定。
  • 下图代码进行双重检查:
    单例模型的双重检查机制
    先检查第一遍是否为空,如果为空则上锁,上锁完再判断一次,避免在上锁的过程中被别人给new出来。为什么要先检查一遍是否为空:因为如果第一次判断不为空,后面就不用上锁,下面的代码就不用执行了。