线程安全的单例模式(双重检查锁方式)

Posted gtshare

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程安全的单例模式(双重检查锁方式)相关的知识,希望对你有一定的参考价值。

在web应用中服务器面临的是大量的访问请求,免不了多线程程序,但是有时候,我们希望在多线程应用中的某一个类只能新建一个对象的时候,就会遇到问题。

首先考虑单线程,如果要求只能新建一个对象,那么构造函数我们要设为private。简单的想法:
技术分享图片
class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance;
  public static singleton getinstance(){
    if(instance==null)            //1
    instance = new singleton();  //2
    return instance
  }
}
技术分享图片
这对于单线程是合理的,第一次调用singleton类时,会新建出singleton对象,但之后访问时,返回的是第一次新建的instance。
但多线程访问时,有可能同时进入//1处的条件判断,多次执行2代码,从而新建多个singleton对象。我们考虑使用同步关键字sycronized
技术分享图片
class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance;
  public static singleton synchronized getinstance(){
    if(instance==null)            //1
      instance = new singleton();  //2
    return instance
  }
}
技术分享图片
此时可以保证不出错,是单例模式的一种方案,但是问题是每次执行都要用到同步,开销较大。
另外一种想法是,双重检查锁,代码如下:
技术分享图片
class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance;
  public static singleton  getinstance(){
    if(instance==null) {           //1
      sycronized(singleton.class){
        if(instance==null)
          instance = new singleton();  //2
       }
    }
    return instance;
  }
}
技术分享图片
此写法保证了,当多个进程进入第一个判断锁时,会被同步机制隔离,只有一个程序进入新建对象,再其他线程进入时,instance已经不为null,因此不会新建多个对象。这种方法就叫做双重检查锁,但是也有一个问题,就是java是实行无序写入的机制,在某个线程执行//2代码的过程中,instance被赋予了地址,但是singleton对象还没构造完成时,如果有线程访问了代码//1此时判断instance不为空,但是方法返回的是一个不完整对象的引用。此时可能会产生错误!
另外一种实现单例模式(懒汉)的写法就是
技术分享图片
class singleton{
  private singleton(){
    //.....
  }
  private static singleton instance = new singleton();
  public static singleton  getinstance(){
    return instance;
  }
}
技术分享图片
这样就不会有之前的问题了。
 
另外单例模式还有 内部类方式的写法 可自行百度。
 

以上是关于线程安全的单例模式(双重检查锁方式)的主要内容,如果未能解决你的问题,请参考以下文章

多线程 实现单例模式 ( 饿汉懒汉 ) 实现线程安全的单例模式 (双重效验锁)

单例模式双重检查(DCL)引发的多线程问题

单例陷阱——双重检查锁中的指令重排问题

多线程下的单例模式详解

多线程下的单例模式详解

单例模式双重检查锁模式为什么必须加 volatile?