建立執行緒安全的單例模式
單例模式的概念
單例模式就是確保只有一個例項,而且自行例項化並向整個系統傳遞這個例項,這個類就稱作單例類
單例模式最重要的一個特點就是構造方法私有化,單例模式分為懶漢式和餓漢式;
第一種:懶漢式(執行緒不安全)
傳統的懶漢式建立單例模式,是執行緒不安全的
public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
懶漢式單例就是在呼叫的時候才去建立這個例項,這種寫法的懶載入很明顯,但缺點就是不能在多執行緒訪問下正常工作。
第二種:懶漢式(執行緒安全的)
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
執行緒安全的方式建立單例就是在對外的建立例項方法上加上synchronized(同步),這種寫法能夠在多執行緒中很好的工作,且看起來也具備很好的lazy loading,但是,效率很低,99%情況下不需要同步。
第三種:懶漢式(執行緒安全的)
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
這種方式基於classloader機制避免了多執行緒的同步問題,不過,instance在類裝載時就例項化,雖然導致類裝載的原因有很多種,在單例模式中大多數都是呼叫getInstance方法,但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載,這時候初始化instance下安然沒有達到lazy loading 的效果。
第四種:靜態內部類的方式建立單例模式
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {// 靜態內部類
private static Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
}
這中方式同樣利用;額classloader的機制來保證初始化instance時只有一個執行緒,它跟第三種方式不同的是(細微的差別):第三種方式是隻要singleton類被裝載了,那麼instance就會被初始化(沒有達到lazy loader效果),而這種方式是singleton類被裝載了,instance不一定被初始化,因為singleHolder類沒有被主動使用,只有顯示通過呼叫getInstance方法時,才會顯示裝載SingletonHolder類,從而例項化singleton。如果例項化singleton很消耗資源,想讓它延遲載入,另外一方面,不希望在singleton來載入時就例項化,因為我不能確保Singleton類還可能在其他的地方被主動使用從而被載入,那麼這個時候例項化instance顯然時不合適的,這個時候,這個時候,這種方式相比第三種方式就顯得很合理。
第五種:雙重校驗鎖
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance(){
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
/**
* 為什麼這裡會使用雙重判定呢?
*/
singleton = new Singleton();
}
}
}
return singleton;
}
}
這種是用雙重判斷來建立一個單例的方法,那麼為什麼要使用兩個if判斷當前是不是空的呢?因為當有多個執行緒同時要建立物件的時候,多個執行緒有可能都停止在第一個if判斷的地方,等待鎖的釋放,然後多個執行緒就都建立了物件,這樣就不是單例模式了,所以要用兩個if來進行這個物件是否存在的判斷。