寫出一個單例模式(Singleton Pattern)
public final class EagerSingleton
{
private static EagerSingleton singObj = new EagerSingleton();
private EagerSingleton(){
}
public static EagerSingleton getSingleInstance(){
return singObj;
}
}
這種寫法就是所謂的饑餓模式,每個對象在沒有使用之前就已經初始化了。這就可能帶來潛在的效能問題:如果這個對象很大呢?沒有使用這個對象之前,就把它載入到了記憶體中去是一種巨大的浪費。針對這種情況,我們可以對以上的代碼進行改進,使用一種新的設計思想——消極式載入(Lazy-load Singleton)。
public final class LazySingleton
{
private static LazySingleton singObj = null;
private LazySingleton(){
}
public static LazySingleton getSingleInstance(){
if(null == singObj) singObj = new LazySingleton();
return singObj;
}
}
這種寫法就是所謂的懶漢模式。它使用了消極式載入來保證對象在沒有使用之前,是不會進行初始化的。這種寫法安全執行緒嗎?不安全。這是因為在多個線程可能同時運行到if(null == singObj),判斷singObj為null,於是同時進行了初始化。所以,這是面臨的問題是如何使得這個代碼安全執行緒?很簡單,在那個方法前面加一個Synchronized就OK了。
public final class ThreadSafeSingleton
{
private static ThreadSafeSingleton singObj = null;
private ThreadSafeSingleton(){
}
public static Synchronized ThreadSafeSingleton getSingleInstance(){
if(null == singObj ) singObj = new ThreadSafeSingleton();
return singObj;
}
}
這個寫法有沒有什麼效能問題呢?答案肯定是有的!同步的代價必然會一定程度的使程式的並發度降低。那麼有沒有什麼方法,一方面是安全執行緒的,有可以有很高的並發度呢?
我們觀察到,線程不安全的原因其實是在初始化對象的時候,所以,可以想辦法把同步的粒度降低,只在初始化對象的時候進行同步。這裡有必要提出一種新的設計思想——雙重檢查鎖(Double-Checked Lock)。
public final class DoubleCheckedSingleton
{
private static DoubleCheckedSingletonsingObj = null;
private DoubleCheckedSingleton(){
}
public static DoubleCheckedSingleton getSingleInstance(){
if(null == singObj ) {
Synchronized(DoubleCheckedSingleton.class){
if(null == singObj)
singObj = new DoubleCheckedSingleton();
}
}
return singObj;
}
}
這種寫法使得只有在載入新的對象進行同步,在載入完了之後,其他線程在第九行就可以判斷跳過鎖的的代價直接到第15行代碼了。做到很好的並發度。
上面的寫法一方面實現了Lazy-Load,另一個方面也做到了並發度很好的安全執行緒,一切看上很完美。其實這種寫法還是有問題的!問題在哪裡?假設線程A執行到了第9行,它判斷對象為空白,於是線程A執行到第12行去初始化這個對象,但初始化是需要耗費時間的,但是這個對象的地址其實已經存在了。此時線程B也執行到了第九行,它判斷不為空白,於是直接跳到15行得到了這個對象。但是,這個對象還沒有被完整的初始化!得到一個沒有初始化完全的對象有什麼用!關於這個Double-Checked
Lock的討論有很多,目前公認這是一個Anti-Pattern,不推薦使用!
這裡又要提出一種新的模式——Initialization on Demand Holder. 這種方法使用內部類來做到消極式載入對象,在初始化這個內部類的時候,JLS(Java Language Sepcification)會保證這個類的安全執行緒。這種寫法完全使用了Java虛擬機器的機制進行同步保證,沒有一個同步的關鍵字。
public class Singleton
{
private static class SingletonHolder
{
public final static Singleton instance = new Singleton();
}
public static Singleton getInstance()
{
return SingletonHolder.instance;
}
}
提供一些連結For your reference:
Double-Checked Lock:http://en.wikipedia.org/wiki/Double-checked_locking
Initialzation on Demand Holder:
http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
原帖地址:http://blog.sina.com.cn/s/blog_75247c770100yxpb.html