<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    xylz,imxylz

    關(guān)注后端架構(gòu)、中間件、分布式和并發(fā)編程

       :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評(píng)論 :: 0 Trackbacks
    本文將探討單例模式的各種情況,并給出相應(yīng)的建議。單例模式應(yīng)該是設(shè)計(jì)模式中比較簡單的一個(gè),但是在多線程并發(fā)的環(huán)境下使用卻是不那么簡單了。
    首先看最原始的單例模式。
    1 package xylz.study.singleton;
    2 
    3 public class Singleton {
    4 
    5     private static Singleton instance = null;
    6 
    7     private Singleton() {
    8     }
    9 
    10     public static Singleton getInstance() {
    11         if (instance == null) {
    12             instance = new Singleton();
    13         }
    14         return instance;
    15     }
    16 }
    17 

    顯然這個(gè)寫法在單線程環(huán)境下非常好,但是多線程會(huì)導(dǎo)致多個(gè)實(shí)例出現(xiàn),這個(gè)大家都能理解。
    最簡單的改造方式是添加一個(gè)同步鎖。
    1 package xylz.study.singleton;
    2 
    3 public class SynchronizedSingleton {
    4 
    5     private static SynchronizedSingleton instance = null;
    6 
    7     private SynchronizedSingleton() {
    8     }
    9 
    10     public static synchronized SynchronizedSingleton getInstance() {
    11         if (instance == null) {
    12             instance = new SynchronizedSingleton();
    13         }
    14         return instance;
    15     }
    16 }
    17 

    顯然上面的方法避免了并發(fā)的問題,但是由于我們只是在第一次構(gòu)造對象的時(shí)候才需要同步,以后就不再需要同步,所以這里不可避免的有性能開銷。于是將鎖去掉采用靜態(tài)的屬性來解決同步鎖的問題。
    1 package xylz.study.singleton;
    2 
    3 public class StaticSingleton {
    4 
    5     private static StaticSingleton instance = new StaticSingleton();
    6 
    7     private StaticSingleton() {
    8     }
    9 
    10     public static StaticSingleton getInstance() {
    11         return instance;
    12     }
    13 }
    14 

    上面的方法既沒有鎖又解決了性能問題,看起來已經(jīng)滿足需求了。但是追求“完美”的程序員想延時(shí)加載對象,希望在第一次獲取的時(shí)候才構(gòu)造對象,于是大家非常聰明的進(jìn)行改造,也即非常出名的雙重檢查鎖機(jī)制出來了。
    1 package xylz.study.singleton;
    2 
    3 public class DoubleLockSingleton {
    4 
    5     private static DoubleLockSingleton instance = null;
    6 
    7     private DoubleLockSingleton() {
    8     }
    9 
    10     public static DoubleLockSingleton getInstance() {
    11         if (instance == null) {
    12             synchronized (DoubleLockSingleton.class) {
    13                 if (instance == null) {
    14                     instance = new DoubleLockSingleton();
    15                 }
    16             }
    17         }
    18         return instance;
    19     }
    20 }
    21 


    雙重鎖機(jī)制看起來非常巧妙的避免了上面的問題。但是真的是這樣的嗎?文章《雙重檢查鎖定及單例模式》中談到了非常多演變的雙重鎖機(jī)制帶來的問題,包括比較難以理解的指令重排序機(jī)制等。總之就是雙重檢查鎖機(jī)制仍然對導(dǎo)致錯(cuò)誤問題而不是性能問題。

    一種避免上述問題的解決方案是使用volatile關(guān)鍵字,此關(guān)鍵字保證對一個(gè)對象修改后能夠立即被其它線程看到,也就是避免了指令重排序和可見性問題。參考文章

    指令重排序與happens-before法則

    所以上面的寫法就變成了下面的例子。

    package xylz.study.singleton;

    public class DoubleLockSingleton {

        private static volatile DoubleLockSingleton instance = null;

        private DoubleLockSingleton() {
        }

        public static DoubleLockSingleton getInstance() {
            if (instance == null) {
                synchronized (DoubleLockSingleton.class) {
                    if (instance == null) {
                        instance = new DoubleLockSingleton();
                    }
                }
            }
            return instance;
        }
    }


    于是繼續(xù)改造,某個(gè)牛人利用JVM的特性來解決上述問題,具體哪個(gè)牛人我忘記了,但是不是下面文章的作者。
    (1)《Java theory and practice: Fixing the Java Memory Model, Part 2
    (2)《Initialize-On-Demand Holder Class and Singletons

    1 package xylz.study.singleton;
    2 
    3 public class HolderSingleton {
    4 
    5     private static class HolderSingletonHolder {
    6 
    7         static HolderSingleton instance = new HolderSingleton();
    8     }
    9 
    10     private HolderSingleton() {
    11         //maybe throw an Exception when doing something
    12     }
    13 
    14     public static HolderSingleton getInstance() {
    15         return HolderSingletonHolder.instance;
    16     }
    17 }
    18 




    上述代碼看起來解決了上面單例模式遇到的所有問題,而且實(shí)際上工作的很好,沒有什么問題。但是卻有一個(gè)致命的問題,如果第11行拋出了一個(gè)異常,也就是第一次構(gòu)造函數(shù)失敗將導(dǎo)致永遠(yuǎn)無法再次得到構(gòu)建對象的機(jī)會(huì)。
    使用下面的代碼測試下。
    1 package xylz.study.singleton;
    2 
    3 public class HolderSingletonTest {
    4 
    5     private static class HolderSingletonHolder {
    6 
    7         static HolderSingletonTest instance = new HolderSingletonTest();
    8     }
    9 
    10     private static boolean init = false;
    11    
    12     private HolderSingletonTest() {
    13         //maybe throw an Exception when doing something
    14         if(!init) {
    15             init=true;
    16             throw new RuntimeException("fail");
    17         }
    18     }
    19 
    20     public static HolderSingletonTest getInstance() {
    21         return HolderSingletonHolder.instance;
    22     }
    23     public static void main(String[] args) {
    24         for(int i=0;i<3;i++) {
    25             try {
    26                 System.out.println(HolderSingletonTest.getInstance());
    27             } catch (Exception e) {
    28                 System.err.println("one->"+i);
    29                 e.printStackTrace();
    30             }catch(ExceptionInInitializerError err) {
    31                 System.err.println("two->"+i);
    32                 err.printStackTrace();
    33             }catch(Throwable t) {
    34                 System.err.println("three->"+i);
    35                 t.printStackTrace();
    36             }
    37         }
    38     }
    39 }
    40 
    很不幸將得到以下輸出:
    1 two->0
    2 java.lang.ExceptionInInitializerError
    3     at xylz.study.singleton.HolderSingletonTest.getInstance(HolderSingletonTest.java:21)
    4     at xylz.study.singleton.HolderSingletonTest.main(HolderSingletonTest.java:26)
    5 Caused by: java.lang.RuntimeException: fail
    6     at xylz.study.singleton.HolderSingletonTest.<init>(HolderSingletonTest.java:16)
    7     at xylz.study.singleton.HolderSingletonTest.<init>(HolderSingletonTest.java:12)
    8     at xylz.study.singleton.HolderSingletonTest$HolderSingletonHolder.<clinit>(HolderSingletonTest.java:7)
    9      2 more
    10 three->1
    11 java.lang.NoClassDefFoundError: Could not initialize class xylz.study.singleton.HolderSingletonTest$HolderSingletonHolder
    12     at xylz.study.singleton.HolderSingletonTest.getInstance(HolderSingletonTest.java:21)
    13     at xylz.study.singleton.HolderSingletonTest.main(HolderSingletonTest.java:26)
    14 three->2
    15 java.lang.NoClassDefFoundError: Could not initialize class xylz.study.singleton.HolderSingletonTest$HolderSingletonHolder
    16     at xylz.study.singleton.HolderSingletonTest.getInstance(HolderSingletonTest.java:21)
    17     at xylz.study.singleton.HolderSingletonTest.main(HolderSingletonTest.java:26)
    18 

    很顯然我們想著第一次加載失敗第二次能夠加載成功,非常不幸,JVM一旦加載某個(gè)類失敗將認(rèn)為此類的定義有問題,將來不再加載,這樣就導(dǎo)致我們沒有機(jī)會(huì)再加載。目前看起來沒有辦法避免此問題。如果要使用JVM的類加載特性就必須保證類加載一定正確,否則此問題將比并發(fā)和性能更嚴(yán)重。如果我們的類需要初始話那么就需要想其它辦法避免在構(gòu)造函數(shù)中完成。看起來像是又回到了老地方,難道不是么?

    總之,結(jié)論是目前沒有一個(gè)十全十美的單例模式,而大多數(shù)情況下我們只需要滿足我們的需求就行,沒必有特意追求最“完美”解決方案。
    原文[http://www.imxylz.info/p/177.html]

    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2009-12-18 23:15 imxylz 閱讀(7347) 評(píng)論(4)  編輯  收藏 所屬分類: J2EE技術(shù)

    評(píng)論

    # re: 單例模式完全解析 2011-12-06 14:49 漆黑矢牙
    這么鼓搗下去直接崩潰了。。
    雙重鎖妥妥的。  回復(fù)  更多評(píng)論
      

    # re: 單例模式完全解析 2012-10-22 16:00 jmstt
    像 這樣搞下去, 直接吐血而亡了, 平時(shí)寫的代碼一大半都是錯(cuò)誤的,  回復(fù)  更多評(píng)論
      

    # re: 單例模式完全解析 2012-10-22 16:03 jmstt
    《雙重檢查鎖定及單例模式》 開始看著還挺靠譜的, 后來就受不了了, 跟唐僧一樣, 這是不對的, 那樣也是不對的, 瘋了。。。。這樣搞java就是一個(gè)廢物了  回復(fù)  更多評(píng)論
      

    # re: 單例模式完全解析[未登錄] 2012-12-20 16:18 jay
    @jmstt
    不是不能在多線程條件下使用單例模式,而是沒有完美的方式。
    只要getInstance()加上synchronized就可以實(shí)現(xiàn)。并且這個(gè)是只存在于1.6之前的問題。

    1.6之后使用volatile就可以避免【指令重排】問題,《雙重檢查鎖定及單例模式》就可以實(shí)現(xiàn)了。

    -java就是一個(gè)廢物了,這樣的話在沒有深入了解之前,不要亂說啊。  回復(fù)  更多評(píng)論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 亚洲精品国产情侣av在线| 成人免费视频77777| 国产无限免费观看黄网站| 午夜在线免费视频 | 亚洲色av性色在线观无码| 韩国二级毛片免费播放| 日韩毛片免费无码无毒视频观看| 无码人妻精品中文字幕免费东京热| 1000部拍拍拍18勿入免费视频下载 | 国产午夜亚洲精品午夜鲁丝片| 亚洲成av人片不卡无码久久| 亚洲av无码不卡私人影院| 亚洲AV无码之日韩精品| 国产精品亚洲高清一区二区| 亚洲色中文字幕无码AV| 亚洲va久久久噜噜噜久久狠狠| 亚洲视频在线视频| 亚洲国产模特在线播放| 亚洲一区二区三区精品视频| 亚洲中文字幕一二三四区| 亚洲AV无码男人的天堂| 十八禁的黄污污免费网站| 黄床大片免费30分钟国产精品| 国产在线精品一区免费香蕉| 日本免费大黄在线观看| 国产免费一区二区三区| 免费看又爽又黄禁片视频1000| 亚洲国产黄在线观看| 亚洲人成影院在线无码按摩店| 亚洲性天天干天天摸| 国产免费无遮挡精品视频| 亚洲?v无码国产在丝袜线观看| 免费看国产成年无码AV片| 永久免费无码网站在线观看| 免费观看四虎精品国产永久 | 91嫩草免费国产永久入口| 最新免费jlzzjlzz在线播放| 亚洲av无码天堂一区二区三区 | 亚洲精品亚洲人成人网| 亚洲精品亚洲人成在线观看麻豆| 亚洲最大av资源站无码av网址|