大話單例模式

標題概念

單例模式(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開發中我個人推薦使用靜態內部類模式。
單例模式如何暴力破解和防護呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章