Java 多線程編程中單例的實現

來源:互聯網
上載者:User

標籤:

對於普通單線程單例來說,較為容易,只要避免建立多個對象即可,代碼如下:

public class Singleton {      private static Singleton singleton = null;      public static Singleton getInstance(){          if(singleton==null){                   singleton = new Singleton();          }          return singleton;        }  }

這樣既可以避免建立多個對象消耗系統資源,也可以達到惰性載入,即在使用時才會建立對象;

在單線程時,該類可以很完美的解決單例問題,但是到了多線程,該類將會出現問題:

當兩個現成A和B 同時調用單例獲得執行個體時,若A進入getInstance()方法,判斷當前singleton為空白,則進入singleton=new Singeton(),並返回singleton,但是當A進入時,B同時調用,B也會判斷singleton為空白,因為A進入後並沒有初始化完成,所以B同樣會進入初始化代碼,進行初始化並返回singleton,這樣就出現問題了,並沒有實現單例操作。

所以在多線程環境下,我們需要對該代碼進行一點修改,那就是給getInstance方法加上同步鎖,使A和B不能同時進入該方法內,代碼如下:

public class Singleton {      private static Singleton singleton = null;      public static synchronized Singleton getInstance(){          if(singleton==null){                   singleton = new Singleton();          }          return singleton;        }  }

經過修改後,我們發現在出現之前A和B 同時訪問getInstance方法時,若A先進入getInstance方法,由於sychronized的存在,B是不可能進入該方法的,會在A線程執行完成之前將該方法進行加鎖操作,執行完成之後才會允許B進入該方法,而當B進入方法時,singleton已經不再是null,直接返回單例singleton對象;

但是實際上,若多個線程調用時,同步鎖的存在,很大程度上影響程式效能,所以後來有人提出double-checked blocking方法,來降低效能影響:

 

還有一種方法,叫做double-check blocking,代碼如下:

public class Singleton {      private static Singleton singleton = null;      public static Singleton getInstance(){          if(singleton==null){                 synchronized (singleton){                      if(singleton==null){                           singleton = new Singleton();                               }                  }                }          return singleton;        }  }                

經過此次修改,當線程進入getInstance方法後,將會先判斷singleton是否為空白,這樣減少了進入同步塊所花費的資源,降低了資源消耗,提高了效能,

似乎這樣修改以後,即不會造成同步鎖消耗資源,也不會由於多線程同時進入建立多個對象,但是,實際上,從更深一層來講,站在jvm的層面來說,這樣的代碼仍可能發生問題:

由於在執行singleton = new Singleton();時,jvm是分兩步進行的,先是為singleton預留空間,直接賦值給instance,然後才會初始化singleton,建立singleton執行個體,

如果A先進入singleton = new sSingleton(),但是只是分配了空間,並沒有初始化完成,就返回singleton,那麼當B線程進入時,singleton已經不為null,那麼將直接返回已有的singleton,若在singleton真正初始化之前就使用的話,問題就來了,所有 多線程單例模式,又出現了新的解決辦法:

public class Singleton{     private static c lass SingletonContainer{             private static Singleton instance = new Singleton();     }     public static Singleton getInstance(){            return SingletonContainer.instance;     }}

  該方法為通過內部類實現多線程環境中的單例,

JVM內部機制能夠保證當一個類被載入時,這個類的載入過程是安全執行緒的,當我們第一次調用getInstance方法時,JVM能夠保證instance只被建立一次,並且保證初始化完成,這樣我們就不再需要擔心instance沒有被建立完成了,同時實現了惰性載入單例

Java 多線程編程中單例的實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.