單例模式常用寫法總結

2022-09-19 22:36:11 字數 1682 閱讀 2068

目錄靜態內部類寫法

列舉寫法

防序列化攻擊處理

防反射攻擊處理

參考《建立單例模式的x種方法》在網上已經爛大街了,但這麼多方式,會加重我的記憶負擔,所以還得做個比較,把知識點濃縮一下,最終列出了三個比較常見的方法(其實是兩個,只有靜態內部類和列舉沒有隱患,雙檢鎖是有隱患的,請看下文中的防反射攻擊處理一節)

如果想要懶載入:

我更推薦靜態內部類,因為細節少,寫法簡單,不容易錯。

如果不想要懶載入:

推薦列舉,自帶防反射攻擊和防序列化攻擊,寫法簡單。

public class double_check_lock_test 

public static double_check_lock_test getinstance()}}

return instance;

}}

兩個關鍵點,一是volatile防止指令重排,二是synchronized給類上鎖

因為 instance = new point(200,1); 這句話不是原子指令,其實有三步:

1.分配物件記憶體;

2.呼叫構造器,執行初始化;

3.將物件引用賦值給變數。

其中2和3可能發生指令重排,在併發環境下,執行緒a可能會先執行1和3,這時恰好切換到執行緒b,這時執行緒b就會看到乙個不為null,但是沒有完成初始化的物件,此時執行緒b訪問這個物件就會發生異常。(詳細請看雙重檢查鎖單例模式為什麼要用volatile關鍵字?)

public class static_test 

static_test(){}

public static final static_test getinstance()

}

enum  enum_test 

}

在單例類中加上readresolve()方法。

private object readresolve()
在建構函式中加入檢查。如果發現已經建立過,則不再建立。以雙檢鎖為例:

private double_check_lock_test()

}

但是在《j**a單例---反射攻擊單例和解決方法》這篇文章中指出:

如果先通過正常的獲取手段獲取例項,再進行反射攻擊獲取例項,此時是能防得住反射攻擊的。

但如果反過來,先進行反射攻擊獲取例項,再通過正常的獲取手段獲取例項,得到的兩個結果不同。也就是說,對於雙檢鎖來說,這種處理依舊不能防止反射攻擊,網上的部分部落格都是錯的。

還有一種嘗試解決這種反射攻擊的是:在單例裡面加標識屬性,如果例項化之後,標識改變,在構造器裡面判斷標識改變就拋異常,和上面這種氣勢差不多,但是沒用的,反射可以把構造器的許可權放開,同樣可以把屬性的許可權放開,並且修改屬性值,所以這種方式也是不行的

但是這種處理在靜態內部類中,卻不會產生上面雙檢鎖出現的"先進行反射攻擊獲取例項,再通過正常的獲取手段獲取例項,得到的兩個結果不同"的情況。

static_test()

}

具體原因我還沒弄清楚,希望看到的朋友可以解答一下。

雙重檢查鎖單例模式為什麼要用volatile關鍵字?

j**a單例---反射攻擊單例和解決方法

單例模式的常用寫法

單例模式是最常用到的設計模式之一,熟悉設計模式的朋友對單例模式都不會陌生。一般介紹單例模式的書籍都會提到 餓漢式 和 懶漢式 這兩種實現方式。但是除了這兩種方式,本文還會介紹其他幾種實現單例的方式,讓我們來一起看看吧。單例模式有很多種實現方式,下面給出我經常使用的一種方式 單例模式是一種常用的軟體設...

單例模式寫法

單例模式是最常用到的設計模式之一,熟悉設計模式的朋友對單例模式都不會陌生。一般介紹單例模式的書籍都會提到餓漢式和懶漢式這兩種實現方式。但是除了這兩種方式,本文還會介紹其他幾種實現單例的方式,讓我們來一起看看吧。單例模式是一種常用的軟體設計模式,其定義是單例物件的類只能允許乙個例項存在。許多時候整個系...

單例模式幾種寫法

1.餓漢式 public class singleton public static singleton getinstance 2.懶漢式 public class singleton 雙層檢測鎖 public static singleton getinstance return instanc...