面試官:請手寫下幾種常見的單例模式
我:好的(面帶微笑),內心暗喜(送分題)。
沒成想提筆便寫出瞭如此豪放的代碼,不堪回首,請原諒個人不羈!
java
實際編程應用場景中,有一些對象其實咱們只須要一個,好比線程池對象、緩存、系統全局配置對象等。這樣能夠就保證一個在全局使用的類不被頻繁地建立與銷燬,節省系統資源。面試
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
複製代碼
類加載時就初始化實例,避免了多線程同步問題。自然線程安全。編程
其實就是在上面 靜態常量餓漢式 實現上稍微變更了一下,將類的實例化放在了靜態代碼塊中而已。其餘沒區別。緩存
public class Singleton {
private static Singleton instance;
static {
instance = new Singleton();
}
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
複製代碼
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
複製代碼
這是最基本的實現方式,第一次調用才初始化,實現了懶加載的特性。多線程場景下禁止使用,由於可能會產生多個對象,再也不是單例。安全
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
複製代碼
和上面 懶漢式(線程不安全)實現上惟一不一樣是:獲取實例的getInstance()方法上加了同步鎖。保證了多線程場景下的單例。可是效率會有所折損,不過還好。多線程
public class Singleton {
private volatile static Singleton singleton;
private Singleton() {}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
複製代碼
此種實現中不用每次須要得到鎖,減小了獲取鎖和等待的事件。
注意volatile關鍵字的使用,保證了各線程對singleton靜態實例域修改的可見性。spa
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
複製代碼
這種方式下 Singleton 類被裝載了,instance 不必定被初始化。由於 SingletonHolder 類沒有被主動使用,只有經過顯式調用 getInstance 方法時,纔會顯式裝載 SingletonHolder 類,從而實例化 instance。
注意內部類SingletonHolder要用static修飾且其中的靜態變量INSTANCE必須是final的。線程
此篇完。單例模式掌握至此,足以應付「手寫單例」的面試場景。code