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 中,爲每個線程都提供一個對象,實際上是以
空間換時間來實現線程間隔離的。