單例模式有一下特點:
1、單例類只能有一個執行個體。
2、單例類必須自己自己建立自己的唯一執行個體。
3、單例類必須給所有其他對象提供這一執行個體。
單例模式確保某個類只有一個執行個體,而且自行執行個體化並向整個系統提供這個執行個體。在電腦系統中,線程池、緩衝、日誌對象、對話方塊、印表機、顯卡的驅動程式對象常被設計成單例。這些應用都或多或少具有資源管理員的功能。每台電腦可以有若干個印表機,但只能有一個Printer Spooler,以避免兩個列印工作同時輸出到印表機中。每台電腦可以有若干通訊連接埠,系統應當集中管理這些通訊連接埠,以避免一個通訊連接埠同時被兩個請求同時調用。總之,選擇單例模式就是為了避免不一致狀態,避免政出多頭。
首先看一個經典的單例實現。
複製代碼 代碼如下:
public class Singleton {
private static Singleton uniqueInstance = null;
private Singleton() {
// Exists only to defeat instantiation.
}
public static Singleton getInstance() { if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// Other methods...
}
Singleton通過將構造方法限定為private避免了類在外部被執行個體化,在同一個虛擬機器範圍內,Singleton的唯一執行個體只能通過getInstance()方法訪問。(事實上,通過Java反射機制是能夠執行個體化構造方法為private的類的,那基本上會使所有的Java單例實現失效。此問題在此處不做討論,姑且掩耳盜鈴地認為反射機制不存在。)
但是以上實現沒有考慮安全執行緒問題。所謂安全執行緒是指:如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程啟動並執行結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是安全執行緒的。或者說:一個類或者程式所提供的介面對於線程來說是原子操作或者多個線程之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題。顯然以上實現並不滿足安全執行緒的要求,在並發環境下很可能出現多個Singleton執行個體。
複製代碼 代碼如下:
//餓漢式單例類.在類初始化時,已經自行執行個體化
public class Singleton1 {
//私人的預設構造子
private Singleton1() {}
//已經自行執行個體化
private static final Singleton1 single = new Singleton1();
//靜態Factory 方法
public static Singleton1 getInstance() {
return single;
}
}
//懶漢式單例類.在第一次調用的時候執行個體化
public class Singleton2 {
//私人的預設構造子
private Singleton2() {}
//注意,這裡沒有final
private static Singleton2 single=null;
//靜態Factory 方法
public synchronized static Singleton2 getInstance() {
if (single == null) {
single = new Singleton2();
}
return single;
}
}