聊聊Java中的四種單例模式
近期在做支付,一開始圖省事,也是為了調試方便,支付的alipayClient和tradeService都是使用的時候去拿,這樣就會導致創建多次。為了節省資源,統一配置成單例模式。
什麼是單例
Singleton(單例)是設計模式的一種,為了保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
單例特點
- 單例類確保自己隻有一個實例(構造函數私有:不被外部實例化,也不被繼承)。
- 單例類必須自己創建自己的實例。
- 單例類必須為其他對象提供唯一的實例。
單例應用
資源管理器,回收站,打印機資源,線程池,緩存,配置信息類,管理類,控製類,門麵類,代理類通常被設計為單例類。如果程序有多個類加載器又同時使用單例模式就要保證單例的唯一性了。
實現方式
餓漢式
/**
* 餓漢式
* 創建者 科幫網
* 創建時間 2017年5月11日
*
*/
public class Singleton {
private static Singleton instance = new Singleton();
//私有的默認構造子,保證外界無法直接實例化
private Singleton() {}
//提供全局訪問點獲取唯一的實例
public static Singleton getInstance() {
return instance;
}
}
如果開銷比較大,希望用到時才創建就要考慮延遲實例化,就要用後麵的方法了。
如果你想學習Java可以來這個群,首先是二二零,中間是一四二,最後是九零六,裏麵有大量的學習資料可以下載。
懶漢式
/**
* 懶漢式
* 創建者 科幫網
* 創建時間 2017年5月11日
*
*/
public class Singleton {
private static Singleton instance;
//私有的默認構造子,保證外界無法直接實例化
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance==null){
instance = new Singleton();
}
return instance;
}
}
懶漢式(雙重鎖)
“雙檢鎖”(Double-Checked Lock)盡量將”加鎖”推遲,隻在需要時”加鎖”(僅適用於java 5.0 以上版本,volatile保證原子操作)。
happens-before:”什麼什麼一定在什麼什麼之前運行”,也就是保證順序性。
現在的CPU有亂序執行的能力(也就是指令會亂序或並行運行,可以不按我們寫代碼的順序執行內存的存取過程),並且多個CPU之間的緩存也不保證實時同步,隻有上麵的happens-before所規定的情況下才保證順序性。
JVM能夠根據CPU的特性(CPU的多級緩存係統、多核處理器等)適當的重新排序機器指令,使機器指令更符合CPU的執行特點,最大限度的發揮機器的性能.
如果沒有volatile修飾符則可能出現一個線程t1的B操作和另一線程t2的C操作之間對instance的讀寫沒有happens-before,可能會造成的現象是t1的B操作還沒有完全構造成功,但t2的C已經看到instance為非空,這樣t2就直接返回了未完全構造的instance的引用,t2想對instance進行操作就會出問題。
volatile 的功能:
- 避免編譯器將變量緩存在寄存器裏
- 避免編譯器調整代碼執行的順序
優化器在用到這個變量時必須每次都小心地重新讀取這個變量的值,而不是使用保存在寄存器裏的備份
/**
* 懶漢式(雙重鎖)
* 創建者 科幫網
* 創建時間 2017年5月11日
*
*/
public class Singleton {
//使用 volatile 保證可見性
private volatile static Singleton instance;
//私有的默認構造子,保證外界無法直接實例化
private Singleton() {}
public static Singleton getInstance() {
if(instance==null){
synchronized(Singleton.class){
if(instance==null){
instance = new Singleton();
}
}
}
return instance;
}
}
內部類
/**
* 內部類
* 創建者 科幫網
* 創建時間 2017年5月11日
*
*/
public class Singleton {
//私有的默認構造子,保證外界無法直接實例化
private Singleton() {}
/**
* 類級的內部類,也就是靜態的成員式內部類,該內部類的實例與外部類的實例
* 沒有綁定關係,而且隻有被調用到才會裝載,從而實現了延遲加載
*/
private static class SingletonHolder{
/**
* 靜態初始化器,由JVM來保證線程安全
*/
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
最後更新:2017-05-13 08:41:41