1. 程式人生 > >結合JDK源碼看設計模式——享元模式

結合JDK源碼看設計模式——享元模式

系統內存 技術 同時 == span eof 介紹 rabl max

前言

  在說享元模式之前,你一定見到過這樣的面試題

public class Test {

    public static void main(String[] args) {
        Integer a=Integer.valueOf(127);
        Integer b=new Integer(127);
        System.out.println(a==b);
        int c=127;
        System.out.println(a==c);
        System.out.println(b==c);
    }
}

  問你輸出結果是什麽?有些人可能一下就看出了答案是什麽,有些人可能不是特別清楚。那麽一起看下面的文章。我想你很快就能知曉。

一、享元模式定義

  提供了減少對象數量從而改善應用所需的對象結構方式,使用共享技術有效地支持大量細粒度的對象。

二、適用場景

  常用於系統底層開發,以便解決系統的性能問題。像數據庫連接池,裏面都是創建好的連接對象,在這些連接對象中有我們需要的則直接拿來用,避免重新創建。如果沒有我們需要的,則創建一個。

  在一個系統中有大量相似對象需要緩沖池的場景。不需要一直創建一個新的對象,可以直接從緩沖池裏拿。這樣可以降低系統內存,同時提高效率。

三、內部狀態與外部狀態

  內部狀態:

    在享元模式內部,不隨外界的改變而改變。比如說Integer類中的MIN_VALUE和MAX_VALUE兩個值,無論外部傳什麽值。都不會改變這兩個值。技術分享圖片

  外部狀態:

    這就很好理解了,就是隨外部的改變而改變的狀態。比如說Integer類中的value值。

技術分享圖片 四、Integer中的享元模式

  經過上面的介紹,你肯定大概了解了享元模式的概念。那麽我們來看看Integer中的享元模式具體是怎麽樣的吧。

  

public final class Integer extends Number implements Comparable<Integer> {
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            
return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } private final int value; public Integer(int value) { this.value = value; } }

  上面是我簡化了的Integer類。平常在使用Integer類的時候。你是否思考過用valueOf還是用new創建Integer對象。看完源碼就會發現在valueOf這個方法中它會先判斷傳進去的值是否在IntegerCache中,如果不在就創建新的對象,在就直接返回緩存池裏的對象。這個valueOf方法就用到享元模式。它將-128到127的Integer對象先在緩存池裏創建好,等我們需要的時候直接返回即可。所以在-128到127中的數值我們用valueOf創建會比new更快。如果你還想繼續往裏鉆研,可以去看看IntegerCache如何實現。在這裏我們主要說設計模式。看接下來的一個測試代碼及內存分析。

技術分享圖片

  這裏就可以很清晰的看出來a和b的內存不相等。結果當然是false。回到我們的設計模式上來,在實際的場景中我們更多的是完成緩沖池的創建,來達到緩沖池對象裏面復用的功能。就像下面這種情況,盡管我定義了兩個不同的對象,但實際上我指向的是同一塊內存地址,這樣就減少了系統內存,並且使系統的響應速度更快。

技術分享圖片

五、總結

  在享元模式裏我們要理解享元,“享”就表示共享,“元”表示對象。當我們頻繁需要這個對象的時候,我們考慮new,考慮clone等等這些方法。當然這些方法實際上用的場景和這個不一樣。看上面的內存分析就能知道,我們頻繁需要相同的一個範圍內的對象去做某件事情,我們還需要重新創建對象就會有兩個缺點:第一就是內存浪費,第二就是性能稍慢,特別是我這個對象new起來需要響應的時間很長的時候。這時候考慮用享元模式來先創建一個緩沖池會更好。這個緩沖池可以放在容器中進行存儲,當我們需要的時候直接拿出來用即可。一次創建,多次使用。

  在這裏多說一點就是當int類型和Integer比較的時候會自動的拆箱也就是只比較裏面的值大小是否相等,所以上面的答案就是false,true,true。

結合JDK源碼看設計模式——享元模式