生活随笔
收集整理的這篇文章主要介紹了
设计模式_2_单例模式
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
單例模式
單例模式(創建型模式):
涉及到的單一的類,該類只負責自己對象的創建,并且只有單個對象被創建,提供唯一的對象訪問方式,可直接訪問
注: 只能有一個實例作為全局的訪問點, 構造函數私有單例類只能自己創建自己唯一的實例, 必須給所有其他對象提供這一實例; !!!使用synchronized/lock防止多線程同時創建多個實例
主要用于:控制資源,全局使用的類創建/銷毀
優點: 只有一個實例,減少資源開銷,避免對資源的多重占用(寫文件操作)
缺點: 沒有接口,不能被繼承,只關心內部邏輯,不關心外部
使用場景–產品的唯一序列號; web計數器,使用單例將其緩存,不用每次在數據庫中刷新; 創建對象消耗資源, 比如IO,數據庫連接
懶漢模式/餓漢模式—在/不在類內方法構造實例
一般情況下,不建議使用第 1 種和第 2 種懶漢方式,建議使用第 3 種餓漢方式。只有在要明確實現 lazy loading 效果時,才會使用第 5 種登記方式。如果涉及到反序列化創建對象時,可以嘗試使用第 6 種枚舉方式。如果有其他特殊的需求,可以考慮使用第 4 種雙檢鎖方式
給出下面的例子演示懶漢模式與餓漢模式:
public class SinglePatternDemo1 {public static void main(String[] args) {System.out.println(SinglePattern1.getInstance().hashCode());System.out.println(SinglePattern1.getInstance().hashCode());System.out.println(SinglePattern2.getInstance().hashCode());System.out.println(SinglePattern2.getInstance().hashCode());System.out.println(SinglePattern3.getInstance().hashCode());System.out.println(SinglePattern3.getInstance().hashCode());System.out.println(SinglePattern4.getInstance().hashCode());System.out.println(SinglePattern4.getInstance().hashCode());}}//懶漢式 不要求多線程 線程不安全
class SinglePattern1{private static SinglePattern1 instance=null;//構造方法私有處理避免,類可以實例化private SinglePattern1() {}public static SinglePattern1 getInstance() {if(instance==null)return instance=new SinglePattern1();return instance;}public void showMessage() {System.out.println("我是SinglePattern實例");}
}//懶漢式 線程安全 加鎖保證效率低下
class SinglePattern2{private static SinglePattern2 instance=null;private SinglePattern2() {}public static SinglePattern2 getInstance() {synchronized(SinglePattern2.class){if(instance==null)return instance=new SinglePattern2(); return instance;}}
}//餓漢模式, 容易產生垃圾對象, 不需要加鎖,執行效率會提高, 但是會浪費內存
class SinglePattern3{private static SinglePattern3 instance=new SinglePattern3();private SinglePattern3() {}public static SinglePattern3 getInstance() {return instance;}
}//雙檢鎖/雙重檢驗鎖(DCL,double-checked Locking), 一定程度上具有安全性&&高性能
class SinglePattern4{private static SinglePattern4 instance=null;private SinglePattern4() {}public static SinglePattern4 getInstance() {if(instance==null) {synchronized(SinglePattern4.class) {if(instance==null)return instance=new SinglePattern4();}}return instance;}
}//登記式/靜態內部類, 只適用于靜態域延遲使用, 保證類加載的時候減緩實例化,
//并且使得實例不可在其他類加載的情況下, 再一次被加載
class SinglePattern5{private static class SinglePatternX{private static final SinglePattern5 instance=new SinglePattern5();}private SinglePattern5() {}public static SinglePattern5 getInstance() {return SinglePattern5.SinglePatternX.instance;}
}//枚舉,即可以避免多線程, 還能自動支持序列化機制, 不能通過reflection attack調用私有構造法
enum SinglePattern6{instance;public void getMethod() {}
}
demo1線程不安全
demo2線程安全, 但是效率低下
demo3線程安全, 但是容易產生垃圾對象
demo4線程安全, 比demo2的效率增強了一點, 也可使用ReentrantLock處理
demo5線程安全, 完全利用類加載機制, 容易產生垃圾對象
demo6線程安全, 效率一般, 不能支持反射機制調用私有構造
雙檢鎖/雙重檢驗鎖(DCL,double-checked Locking)可能會出現一個問題: 在new的過程中, 發生JVM指令重排, 就是當thread1構造對象的時候, thread2進入構造方法中, 發現object != null, 但是object在thread1下還沒有構造好, 內部的數據還沒有賦值, 此時返回object對象的引用將會出現this指針逃逸, 導致出現問題, 解決方案: 使用volatile修飾引用變量防止指令重排; 再次我也想說明, 可采用枚舉做實例化, 可解決單例模式, 且線程安全
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的设计模式_2_单例模式的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。