【Java學習筆記】線程安全的單例模式及雙重檢查鎖—我的理解

搬之前寫的博客【2014-12-30 16:04】java

在web應用中服務器面臨的是大量的訪問請求,免不了多線程程序,可是有時候,咱們但願在多線程應用中的某一個類只能新建一個對象的時候,就會遇到問題。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;
  }
}
這樣就不會有以前的問題了。
相關文章
相關標籤/搜索