說到單例模式,大家應該都有所了解,懶漢式、餓漢式馬上浮上心頭。
那么懶漢式和餓漢式有什么區別?除了常見的兩種,還有別的實現單例模式的方法嗎?
1、單例模式的概念(個人總結非官方):
單例顧名思義就是程序運行中,最多只能有一個實例化的對象。(至於為什么這里不做介紹)
2、懶漢式、餓漢式的區別:
區別實際上體現在加載時間上,餓漢式是在類加載的時候就加載;懶漢式是需要用到該實例時才加載。
使用餓漢式的話,不管你用不用得到這個實例,它都會在類加載的時候加載;假如我一直沒使用到這個實例,是不是就浪費資源了?
使用懶漢式的話,用到時候才會去加載,資源的利用上更為合理。
總結:如果確定某個單例一定會用上,餓漢式是一種很合適方法;如果不一定會用的某個單例,懶漢式是比較合適的方法。
2、單例模式的實現
2.1、餓漢式
方法1:靜態變量方式(線程安全)
/*1.將構造方法私有化,外部無法使用new構造方法創建實例*/
private Singleton1() {} /*2.內部創建對象*/
private static Singleton1 instence = new Singleton1(); /*3.對外獲取實例的方法*/
public static Singleton1 getInstence() { return instence; }
方法2:靜態代碼塊方式(線程安全)
/*1.將構造方法私有化,外部無法使用new*/
private Singleton2() {} /*2.內部靜態代碼塊中創建對象*/
private static Singleton2 instence; static { instence = new Singleton2(); } /*3.對外獲取實例的方法*/
public static Singleton2 getInstence() { return instence; }
2.1、懶漢式
方法3:簡單判斷非空(多線程並發不安全,單線程無影響)
/*1.將構造方法私有化,外部無法使用new*/
private Singleton3() {} /*2.創建類成員變量instence*/
private static Singleton3 instence; /*3.對外獲取實例的方法,先判斷instence是否為空,為空則創建*/
public static Singleton3 getInstence() { if(instence == null) { instence = new Singleton3(); } return instence; }
不安全的原因:
方法4:synchronized鎖方法(線程安全,但是synchronized鎖了整個方法,下一個線程必須等上一個線程釋放鎖,效率很低,不建議使用)
/*1.將構造方法私有化,外部無法使用new*/
private Singleton4() {} /*2.創建類成員變量instence*/
private static Singleton4 instence; /*3.對外獲取實例的方法,先判斷instence是否為空,為空則創建*/
public static synchronized Singleton4 getInstence() { if(instence == null) { instence = new Singleton4(); } return instence; }
方法5:同步代碼塊(多線程並發不安全)
/*1.將構造方法私有化,外部無法使用new*/
private Singleton5() {} /*2.創建類成員變量instence*/
private static Singleton5 instence; /*3.對外獲取實例的方法,先判斷instence是否為空,為空則創建*/
public static Singleton5 getInstence() { if(instence == null) { synchronized (Singleton6.class) { instence = new Singleton5(); } } return instence; }
不安全原因:與之前的描述一致,雖然它加了鎖,但是實際上沒有起到作用,如果很多線程已經同時進入if語句塊內,結果是一樣的。
方法6:雙重檢查(線程安全)這個方法比較常用
/*1.將構造方法私有化,外部無法使用new*/
private Singleton6() {} /*2.創建類成員變量instence*/
private static volatile Singleton6 instence; /*3.對外獲取實例的方法,雙重判斷*/
public static Singleton6 getInstence() { if(instence == null) { synchronized (Singleton6.class) { if (instence == null){ instence = new Singleton6(); } } } return instence; }
方法7:靜態內部類(線程安全)這個方法比較常用
/*1.將構造方法私有化,外部無法使用new*/
private Singleton7() {} /*2.編寫一個靜態內部類*/
private static class SingletonInstence { private static final Singleton7 INSTENCE = new Singleton7(); } /*3.提供一個靜態公有方法,直接返回SingletonInstence*/
public static Singleton7 getInstence() { return SingletonInstence.INSTENCE; }
方法8:枚舉(線程安全,還可以防止反序列化重新生成的對象,推薦使用)這個方法被大佬推薦使用,至於為啥博主暫時未去了解
public class Singleton8{ } enum Sing{ insance; public void method(){} }
