寫作緣由:對於一個有逼格的程序猿,23種設計模式應該不在話下,爲了擠身逼格程序猿之列,決定系統的學習設計模式
關於設計模式(主要是思想方面)
001.定義:
是一套反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結
002.目的:
爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
設計模式之最簡單模式 ------> 單例模式:
001.定義:
確保單例類只有一個實例,並且這個單例類提供一個函數接口讓其他類獲取到這個唯一的實例
002.生活情景:
古代皇帝,有且只能有一個,多個則會出問題...
男人娶老婆,有且只能有一個,多了則會...
003.編程情景:
如果某個類,創建時需要消耗很多資源,即new出這個類的代價很大;或者是這個類佔用很多內存,如果創建太多這個類實例會導致內存佔用太多,簡單點比如:
配置文件、工具類、線程池、緩存、日誌等等,這些需要保證整個應用中有且只有一個實例
004.分類:餓漢式、懶漢式(代碼已經做了詳細說明)
public class Singleton { //-----------------------------餓漢模式---------------------------- /** * 餓漢式的特點是加載類的時候比較慢,要創建類的唯一的實例,但是運行時獲取 * 對象的速度比較快 * 線程安全 */ //1.將構造方法私有化,不允許外部直接創建對象 private Singleton() { } //2.創建類的唯一實例,使用private、static 修飾 /** * 靜態成員屬於類所有,在類加載的時候他就會執行,不管用戶是否去調用這個實例, * 它都已經加載了,只要類加載了它就加載了。所以我們稱之爲餓漢模式,它要早些吃飽 */ private static Singleton instance = new Singleton(); //3.提供一個用於獲取實例的方法,使用public、static 修飾 public static Singleton getInstance() { return instance; } //-----------------------------懶漢模式---------------------------- /** * 懶漢式的特點是加載類的時候比較快,但是在運行時獲取對象的速度比較慢, * 因爲在用戶第一次獲取的時候會去創建唯一的實例的過程 * 線程不安全 */ //1.將構造方法私有化,不允許外部直接創建對象 private Singleton() { } //2.聲明類的唯一實例,使用private、static 修飾 /** * 在第一個用戶獲取時纔會去創建實例,後期用戶再次獲取時不會再次創建 * 實例,所以稱之爲懶漢式 */ private static Singleton instance; //3.提供一個用於獲取實例的方法,使用public、static 修飾 public static Singleton getInstance() { if (null == instance) { synchronized (Singleton.class) { if (null == instance) { instance = new Singleton(); } } } return instance; } }
005.分析:
根據你的具體需求選擇不同的單例模式
針對懶漢式:
雙重非空判斷保證了程序的健壯性:
第一次判斷是爲了避免不必要的創建
第二次判斷是確保在此之前沒有其他線程進入到sychronized塊創建了新實例
然而問題來了,主要是在instance=new Singleton();
這段代碼上。這段代碼會編譯成多條指令,大致上做了3件事:
(1)給Singleton實例分配內存
(2)調用Singleton()構造函數,初始化成員字段
(3)將instance對象指向分配的內存(此時instance就不是null啦~)
instance
指向具體的內存實例,也可能先把instance
指向內存實例再對實例進行初始化成員字段。考慮這種情況:一開始,第一個線程執行instance=new Singleton();
這句時,JVM先指向一個堆地址,而此時,又來了一個線程2,它發現instance
不是null
,就直接拿去用了,但是堆裏面對單例對象的初始化並沒有完成,最終出現錯誤~
public class Singleton { private volatile static Singleton instance; //將默認的構造函數私有化,防止其他類手動 private Singleton() { } public static Singleton getInstance() { if (instance == null) { sychronized(Singleton.class) { if (instance == null) instance = new Singleton(); } } return instatnce; } }
分析: