概述

有時候有這樣一個需求:一個類對外只提供一個實例,并且只能有一個實例.
這時候就需要引入單例模式這種設計模式

分類

  • 餓漢式
    類加載完成時就完成了對類實例的實例化。
    優(yōu)點:不涉及多線程問題,不需要考慮線程安全問題。
    缺點:類一加載就實例化,提前占用系統資源

  • 懶漢式
    類加載完成時不進行類實例的實例化,而是在類的實例使用的時候才進行實例化。
    優(yōu)點:類一加載不對實例進行實例化,而是在使用時進行實例化。
    缺點:涉及多線程問題,需要考慮線程安全問題

餓漢式

餓漢式天生就是線程安全的,直接用于多線程不會出現問題。
實現代碼:

public class Single {        private static final Single single = new Single();        private Single(){} // 構造方法私有化
        public static Single getInstance() {            return single;
        }
}

懶漢式

懶漢式本身就是非線程安全的,下面的例1展示了非線程安全的懶漢式,例2,3,4是實現懶漢式線程安全的3中方式。

1. 懶漢式(一定存在線程安全問題)

實現代碼:

public class Single {    private static Single single;    private Single(){} // 構造方法私有化
    public static Single getInstance() {        if (single == null) {
            single = new Single();
        }        return single;
    }
}

注意: 在單線程狀態(tài)下,這個懶漢式的單例可以正常工作,但在多線程環(huán)境下,仍然能產生多個實例。這就不符合最初的要求了,可以考慮加入鎖的機制。

2. 懶漢式(在方法上進行 synchronized限制)

實現代碼:

public class Single {    private static Single single;    private Single(){} // 構造方法私有化
    public static synchronized Single getInstance() {        if (single == null) {
            single = new Single();
        }        return single;
    }
}

該解決方案是在 getInstance() 方法上進行的加鎖,同一時間內,只能有一個線程可以進入該方法,在這里就約等于是一個單線程,大大降低了系統的性能。

3. 懶漢式(雙檢測鎖機制)

實現代碼:

public class Single {    private static Single single;    private Single(){} // 構造方法私有化
    public static Single getInstance() {        if (single == null) {            synchronized(Single.class) {                if (single == null) {
                    single = new Single();
                }
            }
        }        return single;
    }
}

該解決方案可以避免每一次獲取實例都要進行排隊獲取,一旦single被實例化之后,就永遠不會進入synchronized代碼塊內。這時候對于系統的性能就不會產生影響,只是在第一次實例化的時候會對系統性能產生影響。
當外部程序想要獲取Single類的實例的時候,會首先判斷一下 single 實例是否為null,然后進行線程控制代碼塊(synchronized 在同一時刻最多只有一個線程執(zhí)行該段代碼),然后內部又進行了一下 single 實例的判斷。然后才進行single實例的實例化操作。
為什么在synchronized代碼塊中又進行了一次 single是否為null的判斷呢?
有這么一種情況就是:同時有2個或者n個線程同時進入 geInstance(), 這時候它們同時進行 single是否為null的判斷,所以都進入了 if 代碼塊內,因為 synchronized只允許單個線程進入,所以有 n-1個線程在synchronized代碼塊外進行等待,當第一個進入synchronized代碼塊的線程實例化出 single對象時,synchronized代碼塊會把后面等待的其它線程依次放進來,這時候single的實例已經被第一個進入的線程實例化了,所以還要進行依次 single的是否為null的判斷,這是必須要進行的,不然就會產生多個實例。

4. 懶漢式(靜態(tài)內部類方式實現)(推薦)

實現代碼如下:

public class Single {    private Single(){} // 構造方法私有化
    private static class SingleInstance {        public static final Single single = new Single();
    }    public static Single getInstance() {        return SingleInstance.single;
    }
}

使用靜態(tài)內部類的特點:加載外部類的時候不對靜態(tài)內部類進行加載,當使用靜態(tài)內部類時才會去加載該類,拋棄了鎖的使用并且不會提前占用系統資源。是目前比較完美的解決方法。

分類: Java

http://www.cnblogs.com/wuqinglong/p/7125518.html