Java設計模式之單例模式
阿新 • • 發佈:2017-09-21
設計 return 線程安全 -s ron none 方法 有一個 ava
一、前言:
轉載需要註明出處: https://i.cnblogs.com/EditPosts.aspx?opt=1
單例模式其實很早之前就已經接觸過了,但都是為了應付面試或者是為了裝X。每過一段時間後,又有些模糊不清了,也仿佛從來沒有項目中使用過,但最近終於有它的用武之地了。
二、單例模式的特點:
-
- 單例類只能有一個實例
- 單例類自己給自己創建一個實例,註意是唯一的一個實例
- 單例類必須給其他對象提供這唯一的實例
三、單例模式分類:
-
- 懶漢模式
懶漢模式即懶加載,第一次被調用前不實例化。對於創建實例代價大,且不一定會使用時,使用懶加載模式可以減少開銷
-
- 餓漢模式
餓漢模式,在類加載的同時實例化對象
四、實現單例模式的各種方法:
-
- 線程不安全的懶漢模式
public class LazySingleton { private LazySingleton() { } private static LazySingleton single; public static LazySingleton getSinton(){ if (single == null ){ single = new LazySingleton(); }return single; } }
這種方法在單線程場景中,是安全的,但在多線程情況中,單例模式未必是單例模式,也就是存在線程安全問題。
-
- 同步方法下的多線程
public class LazySingleton { private LazySingleton() { } private static LazySingleton single; public static synchronized LazySingleton getSinton(){ if(single == null){ single= new LazySingleton(); } System.out.println(Thread.currentThread().getName()+": "+single); return single; } }
使用sychronized修飾獲取實例對象的方法,這種方法可以保證線程安全,但效率不高,每個線程都需要來獲取 對象鎖。
-
- 同步代碼塊的懶漢模式
public class LazySingleton { private LazySingleton() { } private static LazySingleton single; public static LazySingleton getSinton() { if (single == null) { synchronized (LazySingleton.class) { single = new LazySingleton(); } } System.out.println(Thread.currentThread().getName() + ": " + single); return single; } }
由同步方法想到同步代碼塊,但實際上,這種方法並不是線程安全。
解釋:兩個線程A、B,A線程判斷single是空的 ,當獲取到鎖後;B線程開始判斷,發現single是空的;這時A線程又快人一步,創建了一個對象;線程B來了,獲取到鎖,也創建了一個對象。
-
- 雙重檢查的懶漢
public class LazySingleton { private LazySingleton() { } private static LazySingleton single; public static LazySingleton getSinton() { if (single == null) { synchronized (LazySingleton.class) { if(single== null){ single = new LazySingleton(); } } } System.out.println(Thread.currentThread().getName() + ": " + single); return single; } }
針對同步代碼塊的懶漢,雙重檢查的懶漢可以說是最佳的,既保證了線程安全,又不需要每次都獲取鎖資源。(推薦雙重檢查懶漢)
-
- 靜態常量餓漢
public class HungrySingleTon { private HungrySingleTon(){ } private final static HungrySingleTon single = new HungrySingleTon(); public static HungrySingleTon getInstance(){ return single; } }
無線程安全問題,缺點是類裝在完成實例化,若一直未使用,會造成資源浪費。
-
- 靜態代碼塊餓漢模式
public class HungrySingleTon { private HungrySingleTon() { } private static HungrySingleTon single; static { single = new HungrySingleTon(); } public static HungrySingleTon getInstance() { return single; } }
線程安全,與常量餓漢模式一樣,若一直未被使用,會造成資源浪費。
-
- 靜態內部類
public class HungrySingleTon { private HungrySingleTon() { } public static HungrySingleTon getInstance() { return InnerClass.single; } private static class InnerClass { private static final HungrySingleTon single = new HungrySingleTon(); } }
只有調用getInstance()時才會加載靜態內部類。無線程安全問題,也實現了懶加載。
Java設計模式之單例模式