天天看点

你真的了解单例模式吗?你真的认为单例模式很简单吗? 第二篇

你真的了解单例模式吗?你真的认为单例模式很简单吗? 第二篇

  • 2016-08-18 21:25:13

接着说我们的单例故事。

想要解决上面的线程不安全问题,有很多种办法,这里我们一一来探讨。

第一种就是通过synchronized来控制线程安全,将synchronized加在getInstance方法上,

public static synchronized SingleFactory getInstance()

运行下之前的main方法,是不是发现hashCode都一样了?开心吧,这么严重的问题一下子就解决了。

~~~~

再来一盆冷水:

这种做法其实效率很低。因为在任何时候只能有一个线程调用该方法,其余的需要加入等待,阻塞程度可想而知,如何解决这个问题呢?

我们来分析下,一般这种单例模式都会用在什么场合?是不是初始化的时候?

好的,我们姑且就认为是初始化的时候,即第一次调用的时候创建对象,后续只存在调用的操作。那么就印出来我们之前提到的双重检验

锁。

双重检验锁

双重检验锁(double checked locking pattern),是一种使用同步块加锁的方法。之所以称之为双重检验锁,是

因为会有两次检验 instance == null 的操作。一次是在同步块外面,一次是在里面。

先来上代码:

public static SingleFactory getInstance() {

    if (instance == null) {

        synchronized (SingleFactory.class) {

            if (instance == null) {

                instance = new SingleFactory();

            }

        }

    }

    return instance;

}

运行后是不是发现也ok?

好了,我们来说一下为什么要在同步块外面一次,里面又来一次。

因为当我们第一次初始化的时候,可能会有多个线程同时进入外部的if判断中,如果这个时候没有对当前类进行同步块加锁,则很容易就出现多

个实例的状态。因此我们需要在外面做次判断,然后判断里面加上一个同步块。

~~~~

再来一盆冷水。

为啥?上面的代码看起来很严谨,很完美啊,为什么还是不对?

呵呵,too young too simple!

欲知后事,且听下回分解。

单例模式 java 知客 zhike zhikeworld 知客