1.定義:確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。
單例模式的主要關鍵點:
1>構造函數不能對外開放,一般爲private;
2>通過一個靜態方法或者枚舉返回單例類對象。
3>確保單例類的對象有且只有一個,尤其是在多線程環境下。
4>確保單例類對象在反序列化時不會重新構建對象。
2.應用場景:創建一個對象需要消耗資源過多,如要訪問IO和數據庫等資源,這時就要考慮
使用單例模式。
3.實現方式:
1>餓漢式模式(在程序啓動或單例模式類被加載的時候,單例模式實例就已經被創建。)
public class Singleton {
private static final Singleton mInstance = new Singleton();
private Singleton() {
}
public static Singleton getmInstance() {
return mInstance;
}
}
2>懶漢模式(當程序第一次訪問單例模式實例時才被創建。)(不建議使用)
優點:單例只有在使用時才被實例化,在一定程度上節約了資源。
缺點:第一次加載時需要及時進行實例化,反應稍慢,最大的問題是每次調用getInstance都進行
同步,造成不必要的同步開銷。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (instance==null){
instance=new Singleton();
}
return instance;
}
}
3>雙重檢查鎖機制(雙重檢查鎖定模式首先驗證鎖定條件(第一次檢查),只有通過鎖定條件驗證才真正
的進行加鎖邏輯並再次驗證條件(第二次檢查)。)(使用比較多)
優點:資源利用率高,第一次執行getInstance時單例對象纔會被實例化,並且能夠保證線程安全和單例
對象初始化後調用getInstance不再進行同步鎖。
缺點:除此加載時反應稍慢,由於java內存模型的原因偶爾會失敗,在高併發環境下也有一些缺陷,雖
然概率小。
public class Singletons {
private static Singletons sInstance=null;
private Singletons(){}
public void doSomething(){
System.out.println("do sth.");
}
public static Singletons getsInstance(){
if (sInstance==null){
synchronized (Singletons.class){
if (sInstance==null){
sInstance=new Singletons();
}
}
}
return sInstance;
}
}
4>靜態內部類單例模式(通過使用一個私有的靜態內部類,來存儲外部類的單例)(重點推薦)
誕生前景:DCL雖然在一定程度上解決了資源消耗、多餘的同步、線程安全等問題,但還是在
某些情況下會出現失效問題,該問題被稱爲雙重檢查鎖(DCL)失效。
優點:第一次加載Singleton類時並不會初始化sInstance,只有在第一次調用Singleton的getInstance
方法時纔會導致sInstance被初始化。因此第一次調用getInstance方法會導致虛擬機加載SingletonHolder
類,這種方式不僅能確保線程安全,也能保證單例對象的唯一性,同時延遲了單例的實例化。
public class Singleton1 {
private Singleton1(){}
public static Singleton1 getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder{
private static final Singleton1 sInstance=new Singleton1();
}
}
5>枚舉單例
優點:簡便、線程安全、任何情況下都是一個單例。
public enum SingletonEnum {
INSTANCE;
public void doSomething(){
System.out.println("do sth.");
}
}