单例解析

1、普通单例

public class Singleton {    
      //用一个静态变量来记录Singleton类的唯一实例   
      private static Singleton uniqueInstance;   

      private Singleton() {}   

      //注意这个方法也是静态的   
      public static Singleton getInstance() {    
           if(uniqueInstance == null) {   
             uniqueInstance = new Singleton();   
           }   
           return uniqueInstance;   
      }   
}  

问题所在:

  • 线程不安全

2、线程安全的单例1

    //用一个静态变量来记录Singleton类的唯一实例   
    private static Singleton uniqueInstance;   

    private Singleton() {}   

    //注意这个方法也是静态的   
    public static synchronized Singleton getInstance() {    
        if(uniqueInstance == null) {   
             uniqueInstance = new Singleton();   
         }   
         return uniqueInstance;   
    }   

通过增加synchronized关键字到getInstance()方法中,迫使每个线程在进入方法之前,要先等别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。

问题所在:

  • 对1中的单例进行线程安全优化,但同步方法getInstance依然存在实例被创建后重复进入同步方法getInstance,除第一次外,均造成资源浪费
  • 在调用getInstance方法后才正式创建实例

3、线程安全的单例2

public class Singleton {    

    private static Singleton uniqueInstance = new Singleton();

    private Singleton() {}   

    public static Singleton getInstance() {    
         return uniqueInstance;   
    }   
} 

通过调整实例创建的方法在类构造后马上创建实例,提升实例创建速度

问题所在:

  • 在侧重实例返回响应速度的情况下牺牲性能,使用全局静态实例,大大增加消耗

    4、双重校验锁单例

public class Singleton {    

    private volatile static Singleton uniqueInstance;   

    private Singleton() {}   

    public static Singleton getInstance() {    
    if(uniqueInstance == null) { //(1)   
        //只有第一次才彻底执行这里的代码   
       synchronized() {   
          //再检查一次   
          if(uniqueInstance == null)   
            uniqueInstance = new Singleton();   
       }   
    }   
         return uniqueInstance;   
    }   
}

优化点:

  • volatile保证多线程的实例uniqueInstance正确获取
  • synchronized块中代码只在第一次创建实例的时候完整执行,其余线程执行到(1)后等待获取到锁,当进入同步时其它线程已经创建了实例,跳出同步块直接返回实例
  • 既满足了线程安全又满足性能上相对优化
阅读更多
换一批

没有更多推荐了,返回首页