java性能優化--代理--單例

單例模式是一種對象建立模式,用於生產對象的一個具體實例,它能夠確保系統中一個類只產生一個實例。該模式能帶來兩大好處: java

    1. 對於頻繁使用的對象,能夠省略建立對象所花費的時間。 多線程

    2. 因爲new的次數減小,於是對系統內存的使用頻率也會下降,這將減輕GC壓力、縮短gc停頓時間 函數

單例模式的核心,在於經過一個接口返回惟一的對象實例。一個簡單的單例實現: 工具


public class Singleton {
	private Singleton(){
		System.out.println("create a Singleton");
	}
	
	private static Singleton instance = new Singleton();

	public static Singleton getInstance(){ return instance;
	}
}
  首先,單例必須有一個private訪問級別的構造函數,只有這樣,才能確保單例不會在系統中的其餘代碼內被實例化;其次,instance成員變量和getInstance()的方法必須是static的



這種實現方式很簡單而且仍是十分可靠的,它惟一的不足就是沒法對instance進行延遲加載,實現延遲的代碼爲 性能

public class LazySingleton {
	private LazySingleton(){
		System.out.println("LazySingleton is create");
	}
	
	private static LazySingleton instance = null;
	public static synchronized LazySingleton getInstance(){
		if(instance == null){
			instance = new LazySingleton();
		}
		return instance;
	}
}
首先,對於靜態變量instance初始值賦予null,確保系統啓動時沒有額外的負載;
其次,get方法必須是同步的,不然在多線程請擴下,可能會屢次建立!
可是因爲引入了同步,其性能會和第一種狀況差了不少,因此這種下降了系統性能的作法,是有點不可取的,因此咱們對其進行改進:
public class StaticSingleton {


 private StaticSingleton(){
 System.out.println("create a StaticSingleton");
 }
 
 private static class SingletonHolder{
 private static StaticSingleton instance = new StaticSingleton();
 }
 
 public static StaticSingleton getInstance(){
 return SingletonHolder.instance;
 }
}
這個實現中,單例模式使用內部類來維護實例,當StaticSingleton被加載時,其內部類不會初始化,故能夠在調用getInstance()方法調用,纔會加載SingletonHolder.同時,因爲實例的創建實在類加載時完成,故天生對多線程友好
一般狀況下上面的代碼能夠確保系統中惟一實例。可是仍有意外狀況,好比利用反射,這種狀況咱們不討論,咱們討論一種合理的方法:
public class SerSingleton implements Serializable {


 String name;
 private SerSingleton(){
 System.out.println("create a SerSingleton");
 name = "SerSingleton";
 }
 
 private static SerSingleton instance = new SerSingleton();
 public static SerSingleton getInstance(){
 return instance;
 }
 
 public static void createString(){
 System.out.println("createString in Singleton");
 }
 
//	private Object readResolve(){
//		return instance;
//	}
}
// TODO Auto-generated method stub
 SerSingleton s1 = null;
 SerSingleton s  = SerSingleton.getInstance();
 //先將實例串行化到文件
 FileOutputStream fos = new FileOutputStream("s.txt");
 ObjectOutputStream oos = new ObjectOutputStream(fos);
 oos.writeObject(s);
 oos.flush();
 oos.close();
 
 //從文件讀出
 FileInputStream fis = new FileInputStream("s.txt");
 ObjectInputStream ois = new ObjectInputStream(fis);
 s1= (SerSingleton) ois.readObject();
//		Assert.assertEquals(s,s1);
 System.out.println(s.equals(s1));
若是在第一段代碼中去掉readResovle(),那麼測試代碼(通過串行化和反串行化)後,s和s1指向了不一樣的實例;加上以後便解決該問題。
即便構造函數是私有的,可序列化工具依然能夠經過特殊的途徑去建立類的一個新的實例。序列化操做提供了一個很特別的鉤子(hook)-類中具備一個私有的被實例化的方法readresolve(),這個方法能夠確保類的開發人員在序列化將會返回怎樣的object上具備發言權。足夠奇怪的,readresolve()並非靜態的,可是在序列化建立實例的時候被引用。
相關文章
相關標籤/搜索