最簡單的單例「餓漢式」 web
public class Singleton{安全
private static Singleton instance=new Singleton();
//other fields
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
//other methods
}
出於性能等方面的考慮,但願延遲實例化單例對象(static 屬性在加載類時會被初始化),方案二應運而生,稱之爲「懶漢式」多線程
public class Singleton {
private static Singleton instance=null;
// 私有構造方法,防止從外部使用 new 方法建立對象
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
不幸的是,在高併發的環境中,getInstance()方法返回了多個指向不一樣的該類實例,也就是說:線程不安全。
線程安全寫法A
public class Singleton {
private static Singleton instance=null;
// 私有構造方法,防止從外部使用 new 方法建立對象
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
方案A中雖然實現了多線程的安全訪問,但在多線程高併發訪問狀況下,加上 synchronized關鍵字會使得性能大不如前。
線程安全寫法B併發
public class Singleton {
private static volatile Singleton instance=null;
// 私有構造方法,防止從外部使用 new 方法建立對象
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class){
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
方案B,咱們稱之爲 Double-Checked Locking (雙重檢查加鎖)模式。在此方案中,仍是使用 synchronized,只不過此次只是保證明例化的這段邏輯被一個線程執行。
前述的方法都存在小小的缺陷,有沒有一種既能實現延遲加載,又能實現線程安全的方案呢高併發
終極方案性能
public class Singleton{
private Singleton(){} private static class LazyHolder{ private static final Singleton instance = new Singleton(); } public static Singleton getInstance(){ return LazyHodler.instance; }}