1. 程式人生 > >設計模式-建立型模式-單例

設計模式-建立型模式-單例

單例模式保證一個類只有一個物件,並且提供一個訪問該例項的全域性訪問點。

1.單例模式例項一(餓漢式)

public class Singleton {
	private static Singleton sin = new Singleton(); /// 直接初始化一個例項物件
	private Singleton() { /// private型別的建構函式,保證其他類物件不能直接new一該物件的例項
	}
	public static Singleton getSin() { /// 該類唯一的一個public方法
		return sin;
	}
}

上述程式碼中的一個缺點是該類載入的時候就會直接

new 一個靜態物件出來,當系統中這樣的類較多時,會使得啟動速度變慢。現在流行的設計都是講延遲載入,我們可以在第一次使用的時候才初始化第一個該類物件。 

2單例模式例項二(懶漢式)

public class Singleton {
	private static Singleton instance;
	private Singleton() {
	}
	public static synchronized Singleton getInstance() { // 對獲取例項的方法進行同步
		if (instance == null)
			instance = new Singleton();
		return instance;
	}
}

3單例模式例項三(雙重同步鎖,不推薦可能有問題)

public class Singleton {  
    private static Singleton instance;  
    private Singleton (){
    }   
    public static Singleton getInstance(){    //對獲取例項的方法進行同步
      if (instance == null){
         synchronized(Singleton.class){
             if (instance == null)
                 instance = new Singleton(); 
     }
     }
     return instance;
   }
}

這裡面的疑問可能是為什麼要做兩次判斷和鎖定Singleton.class
問題一:兩個執行緒同時訪問,當執行緒A的執行緒B同時訪問,都獲得instancenull,只有一個執行緒可以鎖定Singleton.class,假設A執行完畢,獲得物件,B被喚醒在進行訪問時不判斷一次,那麼就new 出了一個新物件。
問題二:因為是靜態方法,所以它只有class可以鎖定,沒有this鎖定。

4.單例模式例項四(使用靜態內部類)

public class Singleton {
	private Singleton() {
	}
	public static Singleton getInstance() {
		return Inner.s;
	}
	private static class Inner{
		static Singleton s = new Singleton();
	}
}

你可能認為這與第一種相同,焦點在於是不是延遲載入,靜態內部類對於外部成員只有在第一次呼叫時才被載入。

破解單例模式(不能破解列舉單例)

單例模式可以通過反射或反序列化進行破解
舉例程式碼如下

Class clazz = (Class) Class.forName("com.singleton.Singleton");
Constructor<Singleton> con = clazz.getDeclaredConstructor(null);
con.setAccessible(true);//跳過許可權檢查
Singleton s = con.newInstance(null);
System.out.println(s);