記憶體媽媽太累了,再也撐不起太多的物件了。
何為單例設計模式:
顧名思義,單:表示一個;例:表示例項;單例:表示一個例項;也就是說我們的程式在執行的整個生命週期中,只建立一個物件,而不去建立多個物件。理解起來很簡單吧。
何種場景只需要一個物件?
保證第一點,沒有多個執行緒度這個物件的變數進行寫操作,只要滿足這一點,基本上都可以使用單例設計模式。比如:配置類,Spring中配置的Controller、Service、dao層的物件。
單例設計模式的特徵:
不管你程式碼怎麼寫,只要滿足以下特徵即可:
- 構造方法私有化。禁止外部建立物件。
- 提供一個外部訪問的介面。
常見的單例設計模式:
- 懶漢式
- 餓漢式
- 雙重檢測鎖
- 靜態內部類
- 列舉
常見的這五種單例設計模式,也無非就是利用JVM的特性,對何時進行載入,做了簡單的區分。是程式啟動的時候載入?還是類初始化的時候載入?
程式碼具體實現如下:
懶漢式
簡單理解就是不讓jvm啟動的時候對單例進行載入,好處就是節約記憶體。可不嘛,不載入那麼多物件,當然節省記憶體了。
/**
* @ClassName : lazybones 懶漢單例
* @Description : 懶漢設計模式,載入的時候不進行初始化。
*/
public class Lazybones {
private static Lazybones instance;
/** * 私有構造方法,防止外部建立物件 */
private Lazybones() {
}
/** * 外部過去例項的通道。
*
* @return
*/
public static synchronized Lazybones getInstance() {
if (instance == null) {
instance = new Lazybones();
} return instance;
}
}
餓漢式
簡單理解就是JVM啟動的時候就進行載入這個單例物件。好處就是再使用的時候,直接獲取物件進行呼叫即可。因為類只會載入一次,所以物件也只會被建立一次。
/**
* @ClassName : Eager //餓漢單例
* @Description : //類載入的時候,進行初始化。
*/
public class Hungry {
private static Hungry instance = new Hungry();
/**
* 私有構造方法
*/
private Hungry() {
}
/**
* 外部過去例項的通道
* @return
*/
public static Hungry getInstance() {
return instance;
}
}
雙重檢測鎖
其實就是針對懶漢模式的一種優化,我們直接在方法上加鎖,導致每次獲取這個物件的時候,都需要先獲取鎖,效率太低了。 但是雙重檢測鎖有一個坑,後續慢慢的講。
/**
* @ClassName : DoubleDetectionLock //雙重檢測鎖
* @Description : 雙重檢測鎖,優化了懶漢單例模式的效能問題,通過加volatile關鍵是防止出現指令重排序。
*/
public class DoubleDetectionLock {
// volatile關鍵字可以防止指令重排序,避免產生bug
private static volatile DoubleDetectionLock instance;
/**
* 私有構造方法
*/
private DoubleDetectionLock() {
}
/**
* 外部獲取渠道。
* @return
*/
public static DoubleDetectionLock getInstance() {
if (instance == null) {
synchronized (DoubleDetectionLock.class) {
if (instance == null){
instance = new DoubleDetectionLock();
}
}
}
return instance;
}
}
靜態內部類
此方式也滿足懶載入,因為即使內部類只有在自己被呼叫的時候才會進行初始化。而且兼顧使用到了類只被載入一次的特性。
/**
* @ClassName : InnerClass 內部靜態類單例
* @Description : 內部靜態類只有被去呼叫的時候,才進行初始化。
*/
public class InnerClass {
/**
* 私有構造方法
*/
private InnerClass(){
}
/**
* 內部類初始化的時候,建立。
*/
private static class Instance{
private static InnerClass instance = new InnerClass();
}
/**
* 外部獲取的通道
* @return
*/
public static final InnerClass getInstance(){
return Instance.instance;
}
}
列舉類
天然的單例設計模式,這個平常用的不太多
/**
* 列舉也是天然的單例模式
*/
public enum EnumSingleton {
INSTANCE;
}
結尾
單例設計模式差不多,到此為止了。下一篇講講怎麼去破解單例設計模式,以及怎麼去防護。
本作品採用《CC 協議》,轉載必須註明作者和本文連結