1. 程式人生 > >設計模式(Java隨筆)—單例模式

設計模式(Java隨筆)—單例模式

單例模式(Singleton Pattern):5種建立型模式中的一種,有關單例模式的所有建立方法參考:Java單例模式——並非看起來那麼簡單(總結不易,感謝!),本文中,我只對開發中常用的兩種(多執行緒)方法和Java特有的列舉法進行程式碼複寫。

首先,還是貼一下單例的定義吧:

 Ensure a class only has one instance,and provide a global point of access to it.

    保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。

開發常見一:雙重檢驗鎖(jdk1.5以後使用關鍵字volatile才有意義)

使用

volatile的原因(雖然沒看懂,但貼上吧,萬一以後就看懂了呢):Java中的指令重排優化。所謂指令重排優化是指在不改變原語義的情況下,通過調整指令的執行順序讓程式執行的更快。JVM中並沒有規定編譯器優化相關的內容,也就是說JVM可以自由的進行指令重排序的優化。關鍵就在於由於指令重排優化的存在,導致初始化Singleton和將物件地址賦給instance欄位的順序是不確定的。在某個執行緒建立單例物件時,在構造方法被呼叫之前,就為該物件分配了記憶體空間並將物件的欄位設定為預設值。此時就可以將分配的記憶體地址賦值給instance欄位了,然而該物件可能還沒有初始化。若緊接著另外一個執行緒來呼叫getInstance,取到的就是狀態不正確的物件,程式就會出錯。 --------------------- 本文來自 viclee108 的CSDN 部落格 ,全文地址請點選:https://blog.csdn.net/goodlixueyong/article/details/51935526?utm_source=copy

//1、雙重檢驗鎖 jdk1.5以後才能使用關鍵字volatile
	class Singleton1{
		private static volatile Singleton1 instance=null;
		private Singleton1(){}
		public static Singleton1 newInstance(){
			if(instance==null){
				synchronized (Singleton1.class) {
					if(instance==null){
						instance=new Singleton1();
					}
				}
			}
			return instance;
		}
	}

開發常見二:靜態內部類

//2、靜態內部類
	class Singleton2{
		private static class SingletonHolder{
			public static Singleton2 instance=new Singleton2(); 
		}
		private Singleton2(){}
		public static Singleton2 newInstance(){
			return SingletonHolder.instance;
		}
	}

列舉實現單例:

//3、列舉
	enum Singleton3{
		instance;
		public void method(){}
	}

在已知的單例實現方法中,除了列舉法外,都有兩個共同的缺點,我直接貼過來吧;

  1. 需要額外的工作來實現序列化,否則每次反序列化一個序列化的物件時都會建立一個新的例項。
  2. 可以使用反射強行呼叫私有構造器(如果要避免這種情況,可以修改構造器,讓它在建立第二個例項的時候拋異常)。

而列舉類很好的解決了這兩個問題,使用列舉除了執行緒安全和防止反射呼叫構造器之外,還提供了自動序列化機制,防止反序列化的時候建立新的物件。

雙重校驗鎖和靜態內部類的方式可以解決大部分問題,平時工作中使用的最多的也是這兩種方式。列舉方式雖然很完美的解決了各種問題,但是這種寫法多少讓人感覺有些生疏。在沒有特殊需求的情況下,使用雙重校驗鎖和靜態內部類的方式實現單例模式。