單例模式的六種實現和簡單介紹
在實際開發中,我們常會需要使用到單例模式。單例模式的核心就是,一個類只有一個例項。
如何實現只有一個例項呢?關鍵是:建構函式的私有化。
單例模式的實現有很多中,這裡介紹一下常見的六種。
和其他介紹單例的不一樣。我們首先介紹一種不常用的,但是我認為很有潛力,以後的單例實現最常用的方式。那就是使用列舉來實現單例模式。然後才是其他幾種實現。上程式碼:
(1)列舉實現單例:
public enum Singleton { INSTANCE; public void showMessage(){ System.out.println("列舉"); } }
是不是超簡單?超級清晰?使用的時候直接Singleton.INSTANCE。就可以了。
因為這種方式在JDK1.5之後才支援,所以在一些老系統上可能不能用。但是現在JDK10都出來了,所以我認為以後這種方式會最常用。為什麼:1.很簡潔,甚至簡單。2.自動支援序列化機制。3.絕對防止被多次例項化。4.執行緒安全。
Perfect!
(2)懶漢式執行緒不安全:
public class Singleton { private static Singleton instance; private Singleton(){} public static Singleton getInstance() { if(null == instance) { instance = new Singleton(); } return instance; } }
很簡單的一種單例模式,(當然,列舉更簡單)很容裡理解:靜態私有的實體類,私有的構造方法,提供get方法,只需要在第一次呼叫的時候例項化一次。
但是缺點也很明顯,執行緒不安全。多執行緒的情況下就不能正常工作了。
(3)懶漢式執行緒安全:
public class Singleton { private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(null == instance){ instance = new Singleton(); } return instance; } }
和第二種方式的唯一區別就是:在get方法加了鎖synchronized。這樣就執行緒安全了。但是缺點也很明顯,使用鎖之後效能降低了。
(4)餓漢式:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
餓漢式基於classloder的機制實現了執行緒安全。但是在類裝載的時候就載入了例項,浪費記憶體,也不滿足lazy loading的效果。
餓漢式和懶漢式可以見名知義地理解為:懶漢,他很懶,你不去找他他就不給你例項化。餓漢就是餓慌了,你不去找他他都給你例項化好了。
(5)雙重校驗鎖:
public class Singleton {
private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(null == instance){
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
採用雙鎖機制實現單例,多執行緒下也保證安全和高效。但是呢,缺點也很明顯:很複雜。至少對我來說,雙重校驗鎖什麼的根本不明白啊。照著寫還行,要我解釋就···弄不懂了。
(6)靜態內部類:
public class Singleton {
private static class SingletonHolder{
private static final Singleton instance = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonHolder.instance;
}
}
和雙重校驗鎖一樣的效果,但是簡單一些。也是用classloder的機制實現執行緒安全。且類載入的時候不一定例項化單例。
總結:通常情況下,餓漢式的單例已經能滿足日常使用了。有特殊需要的時候可以考慮雙重校驗鎖。有反序列化建立愛你物件的需求的時候使用列舉。不過了,就個人而言,我更喜歡列舉的方式。正如前面所說:1.簡潔。2.支援序列化。3.絕對單例。4.執行緒安全。Perfect!
差不多就是這樣,希望大家能找到自己喜歡、工作適用的單例模式。
最後呢,作者水平有限,有什麼問題大家可以提出來共同探討學習。
差不多就是這樣,祝大家學習愉快。謝謝。
—— by:軒轔 ——