---
# System prepended metadata

title: Singleton
tags: [Singleton, Design Patten]

---

# Singleton
###### tags: `Design Patten` `Singleton`
使用時機 : 在某些情況下，只能使用同一實例來達到目的，否則造成資料上的問題
注意 : 多執行序、反射、序列化

1. **餓漢模式**
instance 為靜態(類)變量，在初始化階段過程中會被收集進< clinit >()方法中，該方法保證同步，因此instance在多執行緒環境不可能被實例化兩次。
缺點是生命週期很長
輕量級物件比較適合

		public final class Singleton{
			private static Singleton instance = new Singleton();
			private Singleton(){};
			private static Singleton getInstance() return instance;
		}

2. **懶漢模式**
與餓漢模式的差別為主動取得時才實例化
		public final class Singleton{
			private static Singleton instance = null;
			private Singleton(){};
			private static Singleton getInstance() {
				if(instance == null){
					instance = new Singleton();
				}
				return instance;
			}
		}

3. **懶漢+同步模式**
	使用排他鎖進行同步，缺點效能不好
		public final class Singleton{
			private static Singleton instance = null;
			private Singleton(){};
			private static synchronized Singleton getInstance() {
				if(instance == null){
					instance = new Singleton();
				}
				return instance;
			}
		}	

4. **Double Check**
滿足了懶加載、instance唯一性，但在多執行緒環境下"可能"會有問題。
在建構Singleton時需要實例化con或者更多其他實例以及自己，根據JVM運行時指令重排序及happen-before規則，他們並沒有前後倚賴的關係，因此當重排序後假如instance最先完成，con未完成實例，而其他執行緒取得的instance的實例並且執行操作可能會導致NullPointerException。

		public final class Singleton{
			private static Singleton instance = null;
			Connection con ; 
			private Singleton(){
				this.con.......
			};
			private static Singleton getInstance() {
				if(instance == null){
					synchronized(Singleton.class){
						if(instance == null ){
							instance = new Singleton();
						}
					}
				}
				return instance;
			}
		}		

5.  Volatitle + Double Check
	解決4.的方法則是加入關鍵字volatile 
	private volatile static Singleton instance = null;
	此關鍵字可防止指令重排序確保instance在最後才實例化

6.  **Holder**
	此模式借助了ClassLoader的特點，透過靜態內部類維護Singleton Object 的 Instance。
	當內部類被主動引用時，會建立Singleton Object的Instance ，且創見過程在Java 編譯時期會被收集至< clinit >()內 ，並且此方法為同步分法，可保證原子性、有序性、可見性，是目前單利設計中最好的設計之一。但使用時必須考慮到反射及反序列化可能帶來的風險或攻擊。

	    public final class Singleton{
			private Singleton(){ //防止反射
			if (Holder.instance != null) throw new IllegalStateException();
			}
			
			private static class Holder{
				private static Singleton instance = new Singleton();
			}
			
			public static Singleton getInstance(){
				return Holder.instance;
			}
		}


7. **列舉模式**
該類型不允許被繼承、線程安全且只能被實例化一次、無法懶加載(需透過間接方式達成懶加載 EX : 內部列舉 )
列舉的序列化及反序列化交由JVM處理，並且不可使用writeReplace、readResolve等方法
	
		public enum Singleton{
			INSTANCE;
			Singleton(){}
			public static Singleton getInstance(){
				return INSTANCE;
			}
		}