Design pattern ——singleton pattern(單例總結深思)

Talk is cheap  Show me the code

個人學習筆記--僅供參考

單例模式可以保證內存裏只有一個實例,減少了內存開銷;可以避免對資源的多重佔用。
單例模式看起來非常簡單,實現起來其實也非常簡單。

總結一下,

前幾章主要講了

餓漢式:

1,經典餓漢式 2靜態代碼塊餓漢式

優點:沒有加任何的鎖、執行效率比較高,在用戶體驗上來說,比懶漢式更好。
缺點:類加載的時候就初始化,不管用與不用都佔着空間,浪費了內存,有可能佔着茅

懶漢式

1,普通懶漢式 :線程不安全

2,  兩種加鎖懶漢式,互斥鎖解決線程安全,synchronized,容易阻塞

3. 雙重檢查鎖,即利用volatile 和 synchronized 關鍵字,保證可見性和原子性,降低阻塞

其他式

1,,靜態內部類方式  ,去除了鎖,線程也是安全的

2.枚舉式   JDK 底層 ,只有一個protected構造方法 ,枚舉式單例也是《Effective
Java》書中推薦的一種單例實現寫法。在JDK 枚舉的語法特殊性,以及反射也爲枚舉保
駕護航,讓枚舉式單例成爲一種比較優雅的實現。

3.註冊式  非線程安全

這些看起開都解決了單例,時間上,通過java 反射機制,序列化和反序列化,都可以破壞。

所以解決方案:

1.不要實現Serializable接口,如果有Serializable ,可以利用構造一個自己的readResolve() 屏蔽新生成的對象

彩蛋:Serializable,生成新對象是從內存中直接拷貝的,不會調用new方法,也叫深度拷貝,

2.反射只需要再構造方法中,判斷返回的實例是不是空的,只允許非空下返回

再由此發散

研究下ThreadLocal
ThreadLocal 不能保證其
創建的對象是全局唯一,但是能保證在單個線程中是唯一的,天生的線程安全

package pattern;

public class ThreadLocalSingleton {
	private ThreadLocalSingleton() {}
	private static final ThreadLocal<ThreadLocalSingleton>  
	     tl= new ThreadLocal<ThreadLocalSingleton>() {
		@Override
		protected ThreadLocalSingleton initialValue() {
			return new ThreadLocalSingleton();
		}
	};
	public static ThreadLocalSingleton getInstance() {
		return tl.get();
		
	}
	public static void main(String[] args) {
		System.out.println(ThreadLocalSingleton.getInstance());
		System.out.println(ThreadLocalSingleton.getInstance());
		System.out.println(ThreadLocalSingleton.getInstance());
		System.out.println(ThreadLocalSingleton.getInstance());
		System.out.println(ThreadLocalSingleton.getInstance());
		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
				ThreadLocalSingleton h1 = ThreadLocalSingleton.getInstance();
				System.out.println(Thread.currentThread().getName() + ":" + h1);

			}
		});
		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {
				ThreadLocalSingleton h2 = ThreadLocalSingleton.getInstance();
				System.out.println(Thread.currentThread().getName() + ":" + h2);

			}
		});
		t1.start();
		t2.start();
		

		System.out.println("End");
	}
  }

結果

pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
pattern.ThreadLocalSingleton@7852e922
End
Thread-1:pattern.ThreadLocalSingleton@28d0be7
Thread-0:pattern.ThreadLocalSingleton@17135162

我們發現,在主線程main 中無論調用多少次,獲取到的實例都是同一個,都在兩個子線
程中分別獲取到了不同的實例。那麼ThreadLocal 是如果實現這樣的效果的呢?我們知
道上面的單例模式爲了達到線程安全的目的,給方法上鎖,以時間換空間。ThreadLocal
將所有的對象全部放在ThreadLocalMap 中,爲每個線程都提供一個對象,實際上是以
空間換時間來實現線程間隔離的。

 

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