學習一下各種設計模式,看以后的用不用得上╮(╯_╰)╭
1. 飽漢式
/** * 飽漢式 * 1. 構造器私有化 * 2. 靜態的私有變數instance * 3. 靜態的public方法 */ public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
懶漢式缺點:不管用不用這個物件,都會實體化,浪費資源;
2 餓漢式
/** * 餓漢式 * 只有在需要獲取實體的時候,才會去實體化 */ public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
惡漢式也帶來了問題,就是執行緒不安全
3. 對餓漢式+synchronized
/** * 餓漢式+synchronized * 只有在需要獲取實體的時候,才會去實體化 */ public class Singleton { private static Singleton instance; private Singleton() { } public synchronized static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
在方法上加鎖會鎖住整個方法,繼續優化一下,只是給new物件的部分代碼加鎖:
/** * 餓漢式+synchronized同步代碼塊 * 只有在需要獲取實體的時候,才會去實體化 */ public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { instance = new Singleton(); } } return instance; } }
但是在同步代碼塊這樣的方式有產生了問題:執行緒A和執行緒B都執行到了同步代碼塊這里,執行緒A先進去,實體化物件instance,釋放鎖,然后執行緒B才進去,于是也實體化了一個instance,于是就有兩個實體了,執行緒不安全
4. 雙重檢測鎖
/** * 雙重檢測鎖 * */ public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
但是上面雙重檢測的方式在超高并發的環境下也有問題,涉及到JVM層面指令重排,這個雙重檢測單例模式加不加volatile是個經典面試題
舉個例子:Singleton instance = new Singleton() 這條指令雖然我們程式員看起來就是一條指令,但是在jvm層面卻是會分解成三條
(1)在java堆中分配空間,創建物件
(2) 給創建的物件初始化賦值
(3)在java堆疊中創建區域變數instance,指向java堆中的物件
在上面(2)和(3)因為指令重排可能交換了順序,執行程序就是(1)-->(3)-->(2),當執行緒A執行到(1)->(3)的時候,此時instance指向的是一個半成品的實體,因為這個實體中的屬性值還沒有初始化;
此時執行緒B來呼叫Singleton.getInstance()就會發現跳過了里面的if陳述句,直接回傳了instance實體,于是在執行緒B中呼叫該實體的方法的時候就會出問題(半成品的物件是什么呢,想一下類加載機制,加載,鏈接(驗證,準備,決議),初始化,在加載,鏈接之后,初始化之前的物件就是半成品的)
可以使用volatile關鍵字進行優化,禁止指令重排;
5.1 雙重檢測鎖+volatile實作單例(完美版)
/** * 雙重檢測+volatile */ public class Singleton { private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
5.2 列舉實作(完美版)
/** * 列舉方式實作 */ public enum SingletonEnum { instance; }
5.3 靜態內部類的方式實作單例(完美版)
/** * 靜態內部類實作單例 */ public class Singleton { private static Singleton instance; private Singleton() { } private static class SingletonHelper { private static final Singleton singleton = new Singleton(); } public static Singleton getInstance() { return SingletonHelper.singleton; } }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/264717.html
標籤:其他
上一篇:執行緒池執行流程
