摘要:單例是應用開發中一種設計模式,主要應用場景為當且僅當系統中只能保留一個對象時使用。本文提出中可以在生產環境中使用的單例設計模式。在的一書中給出了三種單例設計模式采用靜態變量這種寫法使用了私有的構造方法。
應用場景單例是應用開發中一種設計模式,主要應用場景為:當且僅當系統中只能保留一個對象時使用。本文提出4中可以在生產環境中使用的單例設計模式。推薦使用enum的方式。
例如一下應用場景[1]:
1、 Windows的Task Manager(任務管理器)就是很典型的單例模式(這個很熟悉吧),想想看,是不是呢,你能打開兩個windows task manager嗎?
2、網站的瀏覽人數統計,一般也是采用單例模式實現,否則難以同步。
3、應用程序的日志應用,一般都何用單例模式實現,這一般是由于共享的日志文件一直處于打開狀態,因為只能有一個實例去操作,否則內容不好追加。
//todo
在joshua block 的《effective java second edition》 一書中給出了三種單例設計模式
public class TaskManager { public static final TaskManager INSTANCE = new TaskManager (); private TaskManager (){} //... }
這種寫法使用了私有的構造方法。來保證只能有一個實例,但是這種方法也有例外情況,因為,你可以通過反射來調用私有構造方法。這個時候你可以拋出異常。以下代碼僅作為參考。
public class TaskManager { public static final TaskManager INSTANCE = new TaskManager(); private TaskManager() { if (INSTANCE != null) { try { throw new Exception("An object already exists"); } catch (Exception e) { e.printStackTrace(); } } } //... }2、采用靜態方法
public class TaskManager { private static final TaskManager INSTANCE = new TaskManager(); private TaskManager() {} public static TaskManager getINSTANCE() { return INSTANCE; } //... }3、采用enum的方式
這種模式是目前最佳的,因為:
1、JVM會保證enum不能被反射并且構造器方法只執行一次。
2、此方法無償提供了序列化機制,絕對防止反序列化時多次實例化。
3、運行時(compile-time )創建對象(懶加載) // todo 關于cmpile-time和run-time有時間我多帶帶寫一篇文章。
enum是jdk5的特性,現在(2017)web應用普遍在jdk6、7、8,所以可以放心使用。
目前最佳的方式是使用接口的方式(解耦):
interface Resource { Object doSomething(); } public enum SomeThing implements Resource { INSTANCE { @Override public Object doSomething() { return "I am a Singleton nstance"; } }; } class Demo { public static void main(String[] args) { System.out.println(SomeThing.INSTANCE.doSomething()); } }
或者不使用接口的形式
public enum SomeThing { INSTANCE; public void doSomething() { System.out.println("INSTANCE = " + INSTANCE); } } class Demo { public static void main(String[] args) { SomeThing.INSTANCE.doSomething(); } }
也有人用其他的方式,我對這種方法持強烈反對,具體可以參考文獻4,以下代碼僅做參考
class Resource { } public enum SomeThing { INSTANCE; private Resource instance; SomeThing() { instance = new Resource(); } public Resource getInstance() { return instance; } } class Demo { public static void main(String[] args) { System.out.println(SomeThing.INSTANCE.getInstance()); } }
在其他文章中有提到“懶漢”、“惡漢”的名詞,其實懶漢主要就是"懶"加載[注:指在使用時裝載,不使用時不進行裝載]
有人提出這種懶漢設計
public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
很顯然這種設計線程不安全,一般不會使用。
有人又提出了懶漢改進的方法,使其線程安全。
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
這種寫法能夠在多線程中很好的工作,而且看起來它也具備很好的lazy loading,但是,遺憾的是,因為是重量級鎖,效率很低。
于是有人提出了雙重校驗鎖機制,這個用的也比較多。
下面代碼就是用double checked locking 方法實現的單例,這里的getInstance()方法要檢查兩次,確保是否實例INSTANCE是否為null或者已經實例化了,這也是為什么叫double checked locking 模式。
/** * Singleton pattern example with Double checked Locking */ public class DoubleCheckedLockingSingleton{ private volatile DoubleCheckedLockingSingleton INSTANCE; private DoubleCheckedLockingSingleton(){} public DoubleCheckedLockingSingleton getInstance(){ if(INSTANCE == null){ synchronized(DoubleCheckedLockingSingleton.class){ //double checking Singleton instance if(INSTANCE == null){ INSTANCE = new DoubleCheckedLockingSingleton(); } } } return INSTANCE; } }
參考文獻:
[1] Jason Cai, 設計模式之——單例模式(Singleton)的常見應用場景
[2] cantellow, 單例模式的七種寫法
[3] Javarevisited, 單例模式中為什么用枚舉更好
[4] natsumi, Java枚舉實現單例模式
[5] zejian_,深入理解Java枚舉類型(enum)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70238.html
摘要:總結我們主要介紹到了以下幾種方式實現單例模式餓漢方式線程安全懶漢式非線程安全和關鍵字線程安全版本懶漢式雙重檢查加鎖版本枚舉方式參考設計模式中文版第二版設計模式深入理解單例模式我是一個以架構師為年之內目標的小小白。 初遇設計模式在上個寒假,當時把每個設計模式過了一遍,對設計模式有了一個最初級的了解。這個學期借了幾本設計模式的書籍看,聽了老師的設計模式課,對設計模式算是有個更進一步的認識。...
摘要:一基礎接口的意義百度規范擴展回調抽象類的意義想不想通過一線互聯網公司面試文檔整理為電子書掘金簡介谷歌求職記我花了八個月準備谷歌面試掘金原文鏈接翻譯者 【面試寶典】從對象深入分析 Java 中實例變量和類變量的區別 - 掘金原創文章,轉載請務必保留原出處為:http://www.54tianzhisheng.cn/... , 歡迎訪問我的站點,閱讀更多有深度的文章。 實例變量 和 類變量...
摘要:在設計模式中,所有的設計模式都遵循這一原則。其實就是說在應用程序中,所有的類如果使用或依賴于其他的類,則應該依賴這些其他類的抽象類,而不是這些其他類的具體類。使用設計模式是為了可重用代碼讓代碼更容易被他人理解保證代碼可靠性。 這是劉意老師的JAVA基礎教程的筆記講的賊好,附上傳送門 傳智風清揚-超全面的Java基礎 一、面向對象思想設計原則 1.單一職責原則 其實就是開發人員經常說的高...
摘要:關于對于重排序的講解,強烈推薦閱讀程曉明寫的深入理解內存模型二重排序。語義語義單線程下,為了優化可以對操作進行重排序。編譯器和處理器為單個線程實現了語義,但對于多線程并不實現語義。雙重加載的單例模式分析即雙重檢查加鎖。 版權聲明:本文由吳仙杰創作整理,轉載請注明出處:https://segmentfault.com/a/1190000009231182 1. 引言 在開始分析雙重加鎖單...
閱讀 3893·2021-11-17 09:33
閱讀 1201·2021-10-09 09:44
閱讀 403·2019-08-30 13:59
閱讀 3483·2019-08-30 11:26
閱讀 2185·2019-08-29 16:56
閱讀 2855·2019-08-29 14:22
閱讀 3154·2019-08-29 12:11
閱讀 1278·2019-08-29 10:58