设计模式中的单例模式(线程安全)

来源:互联网 发布:软件开发证书含金量 编辑:程序博客网 时间:2024/06/05 14:16

一般利用private 与static建立的单例模式

public class Singleton {

    private static Singleton sin=new Singleton();    ///直接初始化一个实例对象
    private Singleton(){    ///private类型的构造函数,保证其他类对象不能直接new一个该对象的实例
    }
    public static Singleton getSin(){    ///获取实例的public方法    
        return sin;
    }

}

这种方式其中一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢 。

我们想办法在第一次使用的时候才初始化第一个该类对象。 线程安全的单例模式:可以在获取方法加上synchronized 使方法同步,然后判断实例为空时就new一个

public class Singleton {  
     private static Singleton instance;  
     private Singleton (){
         
     }   
     public static synchronized Singleton getInstance(){    //对获取实例的方法进行同步
       if (instance == null)     
         instance = new Singleton(); 
       return instance;
     }
 }

但这种直接在方法级别同步粒度较大影响性能,只要将同步范围缩小到if 和new那两行代码就行了,所以还有种双层判空之后加锁方式:

错误写法:(会导致指令重排序,两次判空都是判断instance实例,导致指令重排,多线程下不安全)

public class Singleton {  
     private static Singleton instance;  
     private Singleton (){
     }   
     public static Singleton getInstance(){    //对获取实例的方法进行同步
       if (instance == null){
           synchronized(Singleton.class){
               if (instance == null)
                   instance = new Singleton(); 
           }
       }
       return instance;
     }
 }

有人会问为什么外面还要判断是否为空,其实很多情况都有了一个实例后是不为空的,就无需再走进下面的同步代码块了。

正确写法:第二次判空操作改为判断临时变量temp,防止指令重排,也可以给instance加volatile关键字

public class Singleton {
   private static Singleton instance = null;

   private Singleton() { }

   public static Singleton getInstance() {
      if(instance == null) {
         synchronzied(Singleton.class) {
            Singleton temp = instance;
            if(temp == null) {
               temp = new Singleton();
               instance = temp
            }
         }
      }

      return instance;
   }
}




0 0