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

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

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

    神奇好望角 The Magical Cape of Good Hope

    庸人不必自擾,智者何需千慮?
    posts - 26, comments - 50, trackbacks - 0, articles - 11
      BlogJava :: 首頁 ::  :: 聯系 :: 聚合  :: 管理

    單例模式的一個疑問

    Posted on 2012-01-10 17:39 蜀山兆孨龘 閱讀(1847) 評論(6)  編輯  收藏 所屬分類: Java SE

    網上很多關于單例模式寫法的文章,不外乎餓漢和懶漢兩種形式的討論。很多人喜歡用懶漢式,因為覺得它實現了延遲加載,可以讓系統的性能更好。但事實果真如此嗎?我對此存疑。

    首先我們檢查一下餓漢和懶漢單例模式最簡單的寫法(這里不討論哪種懶漢寫法更好):

    // 餓漢
    public final class HungrySingleton {
        private static final HungrySingleton INSTANCE = new HungrySingleton();
    
        private HungrySingleton() {
            System.out.println("Initializing...");
        }
    
        public static HungrySingleton getInstance() {
            return INSTANCE;
        }
    }
    
    // 懶漢
    public final class LazySingleton {
        private static LazySingleton INSTANCE;
    
        private LazySingleton() {
            System.out.println("Initializing...");
        }
    
        public static synchronized LazySingleton getInstance() {
            if (INSTANCE == null) {
                INSTANCE = new LazySingleton();
            }
            return INSTANCE;
        }
    }
        

    從理論上來說,HungrySingleton 的單例在該類第一次使用的時候創建,而 LazySingleton 的單例則在其 getInstance() 方法被調用的時候創建。至于網上有人聲稱“餓漢式不管用不用都會初始化”,純屬走路的時候步子邁得太大。誰的加載更遲?如果你只是調用它們的 getInstance() 方法來得到單例對象,則它們都是延遲加載,這樣懶漢式沒有任何意義,而且由于 LazySingleton 采取了同步措施,性能更低(可以說任何懶漢式的性能都低于餓漢式)。當你使用一個單例類的時候,難道第一步不是調用 getInstance() 么?所以在自己的代碼里,我更喜歡用餓漢式。

    下面用一個例子來測試加載順序:

    // 餓漢
    System.out.println("Before");
    HungrySingleton.getInstance();
    System.out.println("After");
    
    // 懶漢
    System.out.println("Before");
    LazySingleton.getInstance();
    System.out.println("After");
        

    輸出結果都是:

    Before
    Initializing...
    After

    那么,懶漢模式還有什么存在意義?如果系統使用了某些需要在啟動時對類進行掃描的框架,使用餓漢式的話,啟動時間比懶漢式更長,如果使用了大量單例類,不利于開發階段。在系統的正式運行階段,所有的單例類遲早都要加載的,總的說來兩者性能持平,但是懶漢式每次都至少多一個判斷,所以越到后期越體現餓漢的優越性。

    最后,推薦下《Effective Java》第二版指出的用枚舉類型實現的餓漢單例模式:

    // 餓漢
    public enum HungrySingleton {
        INSTANCE;
    
        private HungrySingleton() {
        }
    }
    

    這種寫法不但最簡潔,還能輕易擴展為實例數量固定的“多例模式”。


    評論

    # re: 單例模式的一個疑問[未登錄]  回復  更多評論   

    2012-01-11 08:33 by test
    public enum HungrySingleton 不會延遲加載

    # re: 單例模式的一個疑問  回復  更多評論   

    2012-01-11 10:15 by 蜀山兆孨龘
    @test
    只有在第一次用 HungrySingleton 的時候才會加載其單例對象。如果代碼里面不使用這個枚舉,根本不會加載。這還不叫延遲加載?

    # re: 單例模式的一個疑問  回復  更多評論   

    2012-01-11 11:45 by Sakura
    enum是用了java的語法特性

    我們開發組用單例模式時,將實例緩存下來:
    private ModelLocator model = ModelLocator.getInstance();
    每次用時都直接用model,而不是重復的調用getInstance()
    保持這種用法約定的話就達到了Lazy的優勢。
    對象只有第一次使用時才加載,加載后保存在private 成員變量中,
    以后每次用時不會再調用getInstance(),即不會參與多余的判斷和同步的性能消耗。
    如果不Lazy的話,采用框架啟動掃描類時會慢

    java的語法特性,完全可以用enum來實現非Lazy加載,代碼簡潔、可讀性高

    # re: 單例模式的一個疑問  回復  更多評論   

    2012-01-11 13:21 by 蜀山兆孨龘
    @Sakura
    你這種寫法確實達到了延遲的效果,但我并不覺得它有什么大的優勢,除非在你的系統中有相當一部分單例類很難被調用——這幾乎不可能,早晚都會全部加載。

    系統的啟動時間長一點沒關系,在運行的時候時不時卡一下(延遲加載單例)就不太友好了。

    # re: 單例模式的一個疑問[未登錄]  回復  更多評論   

    2012-01-12 09:28 by test
    加載HungrySingleton類的時候就會實例化,這個不叫延遲加載
    加載類的時候不實例化而是真正用到實例的時候實例化才叫延遲加載

    # re: 單例模式的一個疑問  回復  更多評論   

    2012-01-12 10:24 by 蜀山兆孨龘
    @test
    當你使用一個單例類的時候,第一步不是調用 getInstance() 嗎?莫非你還在單例類里面寫了不少靜態工具方法?當然,除非你正在做一個會對類進行掃描的框架。
    主站蜘蛛池模板: 亚洲另类激情综合偷自拍图| 国产成人免费AV在线播放| 95老司机免费福利| 亚洲国产精品成人久久| 久久久久免费看黄a级试看| 亚洲午夜国产精品无码老牛影视| 巨胸喷奶水www永久免费| 亚洲av无码专区国产乱码在线观看 | 亚洲国产精品尤物YW在线观看| 黄色一级视频免费观看| 亚洲国产综合无码一区二区二三区 | 一个人看的www视频免费在线观看| 久久精品国产亚洲Aⅴ香蕉| 四虎国产成人永久精品免费| 免费人成在线观看播放a| 亚洲成亚洲乱码一二三四区软件| 国产精品免费播放| 又黄又大的激情视频在线观看免费视频社区在线 | 久久影视综合亚洲| 免费人成年激情视频在线观看| 久久免费国产精品| 亚洲一区二区三区在线观看蜜桃| 久久不见久久见中文字幕免费| 国产精品亚洲精品日韩电影| 国产亚洲婷婷香蕉久久精品 | 国产精品亚洲专区无码不卡| 美女视频黄免费亚洲| 亚洲综合最新无码专区| 曰批视频免费30分钟成人| 免费大片黄在线观看| 老牛精品亚洲成av人片| 亚洲黄色网站视频| 国产aa免费视频| 国产91色综合久久免费| 国产99精品一区二区三区免费 | 女人18毛片水最多免费观看| 国产黄色片免费看| 一级做a爰全过程免费视频毛片| 丰满妇女做a级毛片免费观看| 免费在线观看自拍性爱视频| 一个人看的免费观看日本视频www|