單例模式

核心作用:
保證一個類只有一個實例,並且提供一個訪問該實例的全局訪問點。

實例:
1.Windows中的任務管理器 2.回收站……

優點:
只生成一個實例,減小了系統性能的開銷
 

五種單例模式的實現方式:
1、餓漢式(線程安全,調用效率高。但是,不能延時加載)
私有屬性static類變量 先初始化(new 新對象)
私有的構造器
開放的方法--->取對象(方法無同步)
 

public class Demo01 {
	//類初始化時,立即加載這個對象。(沒有延時加載優勢)
	//天然線程安全
	private static Demo01 instance = new Demo01(); 
	
	private Demo01(){}
	
	//方法沒有同步,調用效率高
	public static Demo01 getInstance(){
		return instance;
	} 
}

2、懶漢式(線程安全,調用效率不高。但是,可以延時加載)
私有屬性static類變量 不用初始化
私有化構造器
開放方法-->取對象 使用方法時才檢查初始化對象(new) (方法有同步)

public class Demo02 {
	//類初始化時,不初始化這個對象。(延時加載優勢)
	//天然線程安全
	private static Demo02 instance ; 
	
	private Demo02(){}
	
	//方法同步,調用效率不高
	public static synchronized Demo02 getInstance(){
		if(instance==null){
			instance = new Demo02();
		}
		return instance;
	} 
}

3、雙重檢測鎖式(由於JVM底層內部模型原因,偶爾會出現問題,不建議使用)
將同步內容放到下方的if內部
 

public class Demo03 {
	private Demo03(){}
	
	private static Demo03 instance=null;
	
	public static Demo03 getInstance() { 
	    if (instance == null) { 
	      Demo03 sc; 
	      synchronized (Demo03.class) { 
	        sc = instance; 
	        if (sc == null) { 
	          synchronized (Demo03.class) { 
	            if(sc == null) { 
	              sc = new Demo03(); 
	            } 
	          } 
	          instance = sc; 
	        } 
	      } 
	    } 
	    return instance; 
	  } 
}

4、靜態內部類式(線程安全,調用效率高,但是,可以延時加載)
外部類沒有static屬性,不會像餓漢式那樣立即加載對象
只有真正調用getInstance(),纔會加載靜態內部類。

public class Demo04 {
	private static class SingleTonClassInstance{
		private static final Demo04 instance = new Demo04();
	}
	
	public static Demo04 getInstance(){
		return SingleTonClassInstance.instance;
	}
	
	private Demo04(){}
}


5、枚舉單例(線程安全,調用效率高,不能延時加載)
基於JVM實現的
可以天然防止反射和反序列化漏洞

public enum Demo05 {
	//這個枚舉元素,本身就是單例對象!
	INSTANCE;
	
	//添加自己需要的操作!
	public void singletonOperation(){
		……
	}
}

 

需要延時加載:靜態內部類好於餓漢式
不需要延時加載:靜態內部類好於懶漢式

 

測試懶漢式單例模式(如何防止反射和反序列化漏洞):

public class Demo06 implements Serializable{
	//類初始化時,不初始化這個對象。(延時加載優勢)
	//天然線程安全
	private static Demo06 instance ; 
	
	private Demo06(){
		//通過這樣防止反射創建新的對象
		if(instance!=null){
			throw new RuntimeException();
		}
	}
	
	//方法同步,調用效率不高
	public static synchronized Demo06 getInstance(){
		if(instance==null){
			instance = new Demo06();
		}
		return instance;
	} 
	
	//反序列化時,如果定義了readResolve()方法則直接返回方法指定對象。而不再單獨創建新的對象
	private Object readResolve() throws ObjectStreamException{
		return instance;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章