<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 蜀山兆孨龘 閱讀(1848) 評論(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在天堂| 亚洲av日韩av激情亚洲| 日韩免费高清播放器| 亚洲AV中文无码乱人伦在线视色| 国产黄色一级毛片亚洲黄片大全| 亚洲av不卡一区二区三区| 99在线视频免费观看| 永久免费看bbb| 亚洲欧美日韩中文二区| 国产精品视频白浆免费视频| 破了亲妺妺的处免费视频国产| 亚洲精品又粗又大又爽A片| 免费的涩涩视频在线播放| 亚洲AV无码一区二区三区鸳鸯影院| 久久久久成人片免费观看蜜芽 | 深夜A级毛片视频免费| 亚洲AV无码乱码在线观看| 成人免费观看男女羞羞视频| 国产av无码专区亚洲av果冻传媒 | 亚洲色偷偷综合亚洲av78| 宅男666在线永久免费观看| 日本永久免费a∨在线视频| 精品亚洲综合久久中文字幕| 9420免费高清在线视频| 97性无码区免费| 亚洲AV日韩精品久久久久久 | 一区二区三区免费在线观看| 国产精品国产亚洲精品看不卡| 99免费在线观看视频| 亚洲人成网站在线在线观看| 亚洲精品无码专区2| 亚洲6080yy久久无码产自国产| 亚洲国产aⅴ综合网| 亚洲精品免费在线观看| 亚洲人成人无码.www石榴 | 亚洲精品一区二区三区四区乱码| 全免费a级毛片免费看不卡| 色婷婷综合缴情综免费观看| 久久精品亚洲精品国产色婷| 久久国产乱子精品免费女| 亚洲AV成人噜噜无码网站|