構造方法私有化
宣告乙個靜態私有的本類物件
給外部提供乙個靜態方法獲取物件例項
/**
* 餓漢模式
* 類被載入後物件被建立
* * 缺點:沒有懶載入效果
* * @author lixiang
* @date 2023年04月16日 - 11:05
* @history 2023年04月16日 - 11:05 lixiang create.
*/public
class
hungrysingleton
public
static hungrysingleton getinstance()
}
二.懶漢模式
/**
* 懶漢模式
* 呼叫getinstance方法後才建立物件 (延時載入、懶載入)
* * @author lixiang
* @date 2023年04月16日 - 11:13
* @history 2023年04月16日 - 11:13 lixiang create.
*/public
class
lazysingleton
public
static lazysingleton getinstance()
return lazysingleton;
}}
三.雙重校驗鎖
*
** 雙重校驗鎖
* 較常用
* 優點:執行緒安全
* 效率較高
* 延遲載入 **
@author lixiang
*@date
2023年04月16日 -11:
14*@history
2023年04月16日 -11:
14 lixiang create.*/
public
class
doublechecksingleton
public
static doublechecksingleton getinstance()
}}return doublechecksingleton;
}
這裡重點說下雙重校驗鎖模式,為什麼要進行雙重校驗?為什麼加volatile
關鍵字?
容我給你一一道來:1.如果我們去掉第乙個if (null == doublechecksingleton)
校驗,聰明的你肯定發現了**是可以在併發情況下正常執行的,因為有synchronized
來保證我們的執行緒安全。既然用了synchronized
那必然會損耗效能,因為一旦有執行緒進入了synchronized(doublechecksingleton.class){}
塊那後續執行緒就需要阻塞等待。那我們如何在此基礎上來提高效能呢?於是就有了第乙個if (null == doublechecksingleton)
校驗。
2.如果我們去掉第二個if (null == doublechecksingleton)
校驗,此時**就有問題了,問題出在**呢?
假設當doublechecksingleton == null
時來了兩個執行緒a、b同時到達第乙個if (null == doublechecksingleton)
校驗,毫無疑問順利通過校驗執行if
裡面的方法,這時因為synchronized
的緣故只能有乙個執行緒進入另乙個執行緒等待。假設a執行緒進入了synchronized
塊執行了doublechecksingleton = new doublechecksingleton();
結束後,b執行緒再次執行doublechecksingleton = new doublechecksingleton();
顯然這違背了我們單例模式的初衷。
3.如果我們去掉volatile
關鍵字,此時**也是有問題的。在jvm中建立物件和賦值操作是分開進行的,也就是說doublechecksingleton = new doublechecksingleton();
語句是分三步執行的:
1). 分配記憶體空間。
2). 初始化物件。
3). 將doublechecksingleton
指向剛分配好的記憶體位址。
但是jvm並不保證這三個操作的先後順序,也就是說有可能jvm會按照1–>3–>2來執行。這樣就可能出錯了,我們以a、b兩個執行緒為例:
a) a執行緒先進來,由於doublechecksingleton == null
,a執行緒進入了第乙個if判斷,然後進入synchronized
塊,並執行doublechecksingleton = new doublechecksingleton();
b) 由於jvm內部的優化機制,jvm先分出了一些記憶體,並賦值給doublechecksingleton (注意此時jvm還沒有初始化這個例項),此時a執行緒切換到b執行緒。
c) b進行第乙個if判斷,由於此時doublechecksingleton != null
,因此它馬上return doublechecksingleton;
並將結果返回給呼叫該方法的程式。這時b執行緒打算使用doublechecksingleton
例項,卻發現它沒有被初始化,於是錯誤發生了。
volatile
關鍵字足矣另寫一篇部落格,本文不對其進行具體展開了,這裡我們利用的是:對volatile
變數的寫操作,不允許和它之前的讀寫操作打亂順序;對volatile
變數的讀操作,不允許和它之後的讀寫亂序。如果有時間我再另寫一篇部落格深入**一下volatile
關鍵字。
四.靜態內部類
/**
* * 靜態內部類
* * 類的靜態屬性只會在第一次載入類的時候初始化,所以在這裡,jvm幫助我們保證了執行緒的安全性,
* 在類進行初始化時,別的執行緒是無法進入的
* * 優點:懶載入效果
* 執行緒安全
* 效率高
* * @author lixiang
* @date 2023年04月16日 - 14:52
* @history 2023年04月16日 - 14:52 lixiang create.
*/public
class
staticinnersingleton
private
static
class
singletonholder
public
static staticinnersingleton getinstance()
}
五.列舉類
/**
* 列舉類
* 優點:避免多執行緒同步問題
* 防止反序列化重新建立新的物件
*
* @author lixiang
* @date 2023年04月16日 - 14:55
* @history 2023年04月16日 - 14:55 lixiang create.
*/public
enum enumsingleton
總結是對學習的檢驗、沉澱與昇華,如果有問題還請不吝賜教!!! 設計模式 單例Singleton
定義 確保某乙個類只有乙個例項,而且自行例項化並向整個系統提供這個例項。使用場景 確保某個類有且只有乙個物件的場景,例如建立乙個物件需要消耗的資源過多,如要訪問 io 和資料庫等資源。以earth為例,簡單的單例模式可以寫成如下形式。public class earth public earth g...
單例設計模式(singleton)
單例設計模式的概念 作為物件建立模式,檔裡模式確保某個類只有乙個例項物件,而且自行建立例項並向整個系統提供這個例項。這個類稱為單例類!單例模式的提點 1,單例類只能有乙個例項 2,單例類的唯一例項必須自己建立 3,單例類必須向系統提供這個唯一的例項 餓漢單例類 public class eagers...
設計模式 單例Singleton
若是你希望自己寫的程式中的某個類只能有乙個相對應的例項,那麼這個時候就要用到單例模式了。單例模式是一種非常常見的設計模式,實現方法有好幾種,下面將一一介紹 1.懶漢式 public class singleton public static singleton getinstance return ...