Java最給力的單例模式

編程語言 Java 技術 編程界的小學生 編程界的小學生 2017-09-14

一、定義

通俗的解釋:獨一無二的對象,(只有一個實例,而且只能有一個實例存在)

二、要素

1、某個類只能有一個實例(只能被new一次)。

2、他必須自行創建這個實例(自己創建)。

3、他必須自行向整個系統提供這個實例(提供方法取到這個唯一的實例)。

三、應用場景

只是說了幾個典型的,還有好多。

1、線程池、緩存、對話框、處理偏好設置和註冊表的對象、充當打印機、顯卡等設備的驅動程序的對象事實上,這類對象只能有一個實例,若製造出多個實例,就會導致許多問題產生,如資源使用過量或者是不一致的結果等等。

2、資源共享的情況下,避免由於資源操作時導致的性能或損耗等,如上述中的日誌對象。

3、控制資源的情況下,方便資源之間的互相通信。如上初中的線程池。

四、優缺點

優點

1、實例控制:單例模式會阻止其他對象實例化其他自己的單例對象的副本,從而確保所有對象都訪問唯一實例。

2、靈活性:因為類控制了實例化過程,所以類可以靈活更改實例化過程。

缺點

1、開銷:雖然數量很少,但是如果每次對象請求引用時都檢查是否存在類的實例,將仍然需要一些開銷,可以通過使用靜態初始化解決此問題。

2、可能的開發混淆:使用單例對象(尤其在類庫中定義的對象)時,開發人員必須記住自己不能使用new關鍵字實例化對象,因為可能無法訪問庫源代碼,因為應用程序開發人員可能會意外發現自己無法直接實例化此類。

五、種類

1、餓漢式:類一旦加載,就會實例化這個唯一的對象,不管之後用不用此對象,他都會實例化出來,會佔用一定的內存,並且是線程安全的,可以直接應用到多線程場景。

2、懶漢式:類加載期間不會實例化任何實例,而是當調用內部的getInstance()靜態方法時,才會進行實例化操作,好比延遲加載,如果要做的工作較多的話,性能上會有些延遲,並且是線程不安全的。

3、枚舉法:java1.5後新增枚舉。

4、登記式:用的較少,自己上網搜吧

六、實戰

1、餓漢式

Java最給力的單例模式

餓漢式

2、懶漢式

Java最給力的單例模式

懶漢式

大家都發現了,懶漢式存在線程安全的問題,下面介紹三種解決辦法:

(一)直接同步法(簡單粗暴效率低)

Java最給力的單例模式

直接同步法

通過增加synchronized關鍵字到getInstance()方法中,我們迫使每個線程在進入這個方法前,都要先等別的線程離開該方法,這樣嚴重影響了性能(及其不推薦,但卻是最簡單粗暴的辦法)。

(二)雙重檢查加鎖

Java最給力的單例模式

雙重檢查加鎖

volatile:確保當singleton變量被初始化時,(volatile不懂的去自己查資料)多個線程正確的處理singleton變量這種方式徹底解決了方式一的那種低調率問題。只有第一次才徹底執行同步的代碼。(推薦)。如果不是採用java1.5以及以上版本的話,雙重檢查加鎖實現會失效。

(三)靜態內部類方式(我喜歡的方式)

Java最給力的單例模式

靜態內部類方式

利用靜態內部類的機制來初始化實例,靜態內部類只有當被調用的時候才開始首次被加載,所以與餓漢式是不同的,一定要注意區別!(我個人極其推薦)

懶漢式和餓漢式都並非絕對安全,通過反射機制,依舊可以實例化多次。(要想防止反射,可以在構造器中判斷若多次new,就拋出異常)

3、枚舉法

Java最給力的單例模式

枚舉法

枚舉本身就是單例模式。避免了反射和反序列化的漏洞。調用的效率比較高,線程安全,實現簡單。唯一的缺點是沒有實現延時加載。

除了枚舉法,其他都存在反射注入的漏洞。

最後簡單介紹一下JDK裡的單例模式吧

Java最給力的單例模式

Runtime

若有興趣,歡迎來加入群,【Java初學者學習交流群】:458430385,此群有Java開發人員、UI設計人員和前端工程師。有問必答,共同探討學習,一起進步!

歡迎關注我的微信公眾號【Java碼農社區】,會定時推送各種乾貨(純乾貨的東西,並非Java基礎語法這些。)

Java最給力的單例模式

Java碼農社區

相關推薦

推薦中...