標題概念
單例模式(Singleton Pattern)是 Java 中最簡單的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。
這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。
單例模式基本實現
懶漢模式
這是最基本的單例模式,實現了懶加載,但是多線程不安全,沒有添加鎖synchronized,嚴格意義上來說這不算是單例模式。
實現方式
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 = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
以上兩種基本實現方式都有其缺點,那麼我們來改造下吧,別說了 看代碼
講解
public class Singleton {
private static Singleton instance;
private Singleton() {
System.out.println("創建單例模式");
}
public static Singleton getInstance() {
if (instance == null) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread() {
@Override
public void run() {
super.run();
Singleton.getInstance();
}
}.start();
}
}
我們期望的結果應該是
創建單例模式
而實際結果是
創建單例模式
創建單例模式
創建單例模式
創建單例模式
創建單例模式
沒錯就是這樣,不要問爲什麼,這就是多線程的秒處啦
我們都知道無論是什麼語言 java、c、go、dart、.net等最終都會轉化成在CUP執行的一條條指令,如果當前進程下多個線程在執行任務,cpu會快速切換線程。例子中有5個線程(A,B,C,D,E)同時開啓,線程A執行到判斷語句if(instance == null) 時,同時快速切換至B或者C或者D或者E,他們的判斷條件都成立(instance此時還爲空),再次進行多次切換,(線程A、線程B、線程C、線程D、線程E)都進行賦值操作,所以就創建了5個對象
如何解決呢,請看下面
改造
懶漢式加鎖
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;
}
}
內部靜態類模式
當 Singleton 類加載時,靜態內部類 SingletonHolder 沒有被加載進內存。只有當調用 getUniqueInstance() 方法從而觸發SingletonHolder.INSTANCE 時 SingletonHolder纔會被加載,此時初始化 INSTANCE 實例。
這種方式不僅具有延遲初始化的好處,而且由虛擬機提供了對線程安全的支持。
public class Singleton {
private static class Instance {
private static Singleton instance = new Singleton();
}
private Singleton() {
System.out.println("創建單例模式");
}
public static Singleton getInstance() {
return Instance.instance;
}
}
枚舉模式
這是單例模式的最佳實踐,它實現簡單,並且在面對複雜的序列化或者反射×××的時候,能夠防止實例化多次。
public enum Singleton {
INSTANCE;
public void fun(){}
}
總結
單例模式推薦使用靜態內部類和枚舉模式,在Android開發中我個人推薦使用靜態內部類模式。
單例模式如何暴力破解和防護呢?