Head First Pattern之單例模式

          Posted on 2008-09-14 15:40 Lv Yuanfang 閱讀(444) 評論(0)  編輯  收藏

          多線程環境下的單例模式實現

          ----Head First Pattern之單例模式



          單例模式我想大家都比較熟悉,就是在JVM運行期間一個類只有一個實例,任何時候都是取得同一個實例,也就是一個全局變量了。
          單例模式分懶漢式和餓漢式,但是懶漢式的單例在多線程環境下會有同步的問題,下面詳細介紹了用3中方法來解決此問題。
          單例模式具有以下幾個特點:
          1.JVM運行期間有且只有一個實例
          2.構造函數是私有的
          3.通過一個靜態工廠方法來獲得唯一的實例
          4.累內部有一個私有靜態實例,通過靜態工廠方法創建后,每次再調用靜態工廠方法,返回的都是同一個實例

          餓漢式:
          public class Singleton{
          ??? private static Singleton uniqueInstance = new Singleton();
          ??? // 其他實例變量
          ??? private Singleton(){}
          ??? public static Singleton getInstance(){
          ?? ???? return uniqueInstance;
          ?? ?}
          ?? ?
          ??? // 其他方法
          }

          懶漢式:
          public class Singleton{
          ??? private static Singleton uniqueInstance;
          ??? // 其他實例變量
          ??? private Singleton(){}
          ??? public static Singleton getInstance(){
          ?? ???? if(uniqueInstance == null){
          ?? ??? ???? uniqueInstance = new Signleton();
          ?? ??? ?}
          ?? ???? return uniqueInstance;
          ?? ?}
          ?? ?
          ??? // 其他方法
          }

          多線程環境下的單例模式:
          上面的代碼就是最基本的單例模式示例代碼。但是懶漢式單例有一個問題,因為要保證有且僅有一個實例,如果在多線程環境下調用Singleton.getInstance(),就可能會有多個實例!為了解決多線程訪問的問題,有3種解決方法供選擇:

          1.靜態工廠方法加同步關鍵字,這種方法是在對性能要求不高的情況下采用。
          public class Singleton{
          ??? private static Singleton uniqueInstance;
          ??? // 其他實例變量
          ??? private Singleton(){}
          ??? public static synchronised Singleton getInstance(){
          ?? ???? if(uniqueInstance == null){
          ?? ??? ???? uniqueInstance = new Signleton();
          ?? ??? ?}
          ?? ???? return uniqueInstance;
          ?? ?}
          ?? ?
          ??? // 其他方法
          }

          2.始終用餓漢式單例
          public class Singleton{
          ??? private static Singleton uniqueInstance = new Singleton();
          ??? // 其他實例變量
          ??? private Singleton(){}
          ??? public static Singleton getInstance(){
          ?? ???? return uniqueInstance;
          ?? ?}
          ?? ?
          ??? // 其他方法
          }
          餓漢式的方法,會依賴于JVM在加載類的時候,就創建唯一的實例。在每個線程訪問getInstance方法前,唯一實例已經被創建。

          3.用雙檢查鎖來減少懶漢式中靜態方法getInstance的同步開銷
          對public static synchronised Singleton getInstance()的每次調用,都需要同步,而雙檢查鎖的方式只是在第一次創建實例時同步,其他時候并不需要同步。
          public class Singleton{
          ??? private volatile static Singleton uniqueInstance;
          ??? private Singleton(){}
          ??? public static Singleton getInstance(){
          ?? ???? if(uniqueInstance == null){
          ?? ??? ???? synchronised(Singleton.class){
          ?? ??? ??? ???? if(uniqueInstance == null){
          ?? ??? ??? ??? ??? ??? uniqueInstance = new Singleton();
          ?? ??? ??? ??? ?}
          ?? ??? ??? ?}

          ?? ??? ?}
          ?? ???? return uniqueInstance;
          ?? ?}
          }

          如果調用時實例為null,則進入同步區塊,此時再進行判斷,如果還為null,就創建唯一的實例。有可能在一個線程在 if(uniqueInstance == null) 后進入同步區塊前,另一個線程恰好已經創建成功并從同步區塊中出來,這就需要進入同步區塊后,再做uniqueInstance是否為null的判斷。
          同時uniqueInstance需要加volatile關鍵字,保證在創建單例實例時,多個線程能正確處理uniqueInstance變量。

          注意:
          雙檢查鎖的方式在Java1.4及1.4以前版本不能工作!!因此雙檢查鎖只能在Java 5及以上版本才可以使用。
          記得Effictive Java中也提到過雙檢查鎖,也說不能在Java1.4中使用。
          原因是Java 1.4及以前的JVM中對volatile關鍵字的實現允許對雙檢查鎖不合適的同步。(誰能幫我再深入解釋下?)原文是:
          Unfortunately, in Java version 1.4 and earlier, many JVMs contain implementations of the volatile keyword that allow improper synchronization for double-checked locking. If you must use a JVM other than Java 5, consider other methods of implementing your Singleton.



          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           

          posts - 11, comments - 2, trackbacks - 0, articles - 0

          Copyright © Lv Yuanfang

          主站蜘蛛池模板: 马公市| 太湖县| 耒阳市| 北辰区| 海林市| 股票| 黄陵县| 连云港市| 徐水县| 本溪市| 赤壁市| 扎囊县| 南部县| 镇巴县| 阳西县| 达日县| 阜新| 铜川市| 微山县| 上思县| 驻马店市| 巴东县| 泰来县| 台中市| 沙田区| 资兴市| 盐山县| 屯昌县| 准格尔旗| 辽宁省| 彝良县| 安徽省| 海南省| 大宁县| 山阳县| 彭水| 临汾市| 海伦市| 锦州市| 上高县| 罗山县|