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


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

在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;
  }
}
這樣就不會有之前的問題了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM