<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无码一区二区乱子伦as| caoporm超免费公开视频| 亚洲第一成人影院| 美女啪啪网站又黄又免费| 免费看大美女大黄大色| 亚洲AV永久无码精品网站在线观看| 久久精品网站免费观看| 亚洲日本VA午夜在线电影| 在线免费不卡视频| 亚洲人成色777777精品| 国产免费牲交视频| 又硬又粗又长又爽免费看| 久久久久国产成人精品亚洲午夜| 一区二区三区在线免费 | 精品无码国产污污污免费网站国产 | 亚洲人成网站免费播放| 亚洲不卡中文字幕| 成年人性生活免费视频| 国产亚洲精品91| 国产gv天堂亚洲国产gv刚刚碰| 久久精品免费观看| 亚洲国产夜色在线观看| 在线观看亚洲免费| 青青操免费在线观看| 亚洲一区二区三区首页| 四虎成人免费网址在线| 一级看片免费视频囗交| 亚洲精品视频在线观看视频| 成人免费午夜无码视频| 五月天婷婷免费视频| 亚洲成在人天堂在线| 日韩高清免费在线观看| 在线观看人成视频免费无遮挡| 91亚洲精品麻豆| 亚洲精品一级无码中文字幕| 91免费在线播放| 国产一区二区三区亚洲综合| 亚洲av鲁丝一区二区三区|