singleton pattern 單態模式。
這個模式較簡單,就是為了保證乙個類只有乙個例項,用乙個入口來獲取該例項。
例子如下(**來自維基):
class foo
public static helper gethelper()
// other functions and members...
}
由於構造方法設為了私有,所以其它類無法使用new 來生成該類例項,只有通過
該類自己提供的方法來獲取例項。這個獲取例項的方法通總是使用第一次建立的
例項而保證其它類總是使用同乙個例項。
本來很簡單,但是在多執行緒情況下則會有些麻煩。兩個執行緒都有可能執行到了第
6行,這樣就有可能建立2個例項。過程如下(執行緒1簡稱為t1,執行緒2 簡稱t2):
t1 5 (5代表第5行)
t2 5
t1 6
t1 7 (執行緒1返回乙個例項)
t2 6
t2 7 (執行緒2返回另乙個例項)
這樣就破壞了例項唯一性。如果這兩個例項狀態不會變化,倒也無所謂,就是多
花點記憶體養兩個物件。但如果這兩個例項涉及到計數器等狀態變化,就埋下了隱患。
解決辦法是加上同步關鍵字,如下:
public static synchronized helper gethelper()
問題是解決了,但效率卻降低了。因為每次獲取例項都會執行同步運算。實際上
沒必要。一旦例項建立並返回,以後再獲取例項就不會執行第6行。為了發生機率
很小的事件而每次同步的方法,代價太大了。
不同虛擬機器對同步方法的執行效率不同,早期虛擬機器執行同步效率非常的低。現
在改進了很多,但進入執行緒體、離開執行緒體、加鎖、解鎖這些步驟仍然耗費效能。
所以,後來發明了雙檢查鎖模式。(double-checked locking pattern)。在
《designpattern***plained》一書中,作者專門分析了這種方法的優勢,並給出
了**。**如下:
class ustax ;
public static ustax getlnstance ()
}
不想,書上印錯了,這讓很多人包括我迷惑良久。後來書本經過更正,變為如下形式,
class ustax ;
public static synchronized void dosyn()//這句是我加的,為方便接下來的解釋。
}public static ustax getlnstance ()
}
到此,算是萬事大吉了。不料這種雙重檢查模式仍然有問題,並不能解決多執行緒
的問題。由於這本書的廣泛流傳,這種模式也廣為人知。當這種模式的錯誤之處
被發現後,很快就出現了對這種模式廣泛的討伐之聲。可見,影響越大,一旦有
錯,被討伐的力度也就越大。
我們以上面這段**為例,看看問題是怎樣產生的,
t1 10 (執行緒1執行到第10行)
t1 5
t1 6
t2 10
t2 12
也就是說,執行緒1還沒有完全構造完這個物件(還沒有執行第7行),執行緒2就返回
這個半成品物件了。所以,這種謬種流傳的 double-checked locking pattern也
就壽終正寢,不能再被使用了。
那這種多執行緒出現的問題該怎麼做呢,解決方法也很簡單,如下即可,
class ustax ;
public static synchronized void dosyn()
public static ustax getlnstance ()
}
5 Singleton Pattern 單例模式
單例模式主要符合單一職能原則。當乙個類的職責是一定的,而且整個程式中不需要生成第二個此類的物件,而且如果生成第二個此類的物件的話還會有問題 比如我之前寫的聯棋遊戲,裡面的棋盤就應該始終只有乙個物件,如果有兩個會造成混亂 為了防止生成兩個物件,而且節約記憶體,會使用單例模式。使用單例模式的典型場景比如...
單例模式(Singleton Pattern)
在 design patterns elements of resuable object oriented software 中的定義是 ensure a class only has one instance,and provide a global point of access to。它的主...
單例模式(Singleton Pattern)
單例模式確保乙個類只有乙個例項,並提供乙個全域性訪問點。某些物件我們只需要乙個,比如執行緒池 快取 登錄檔等等。如果這些類擁有多個例項,可能會產生很多問題。使用單例模式可以確保我們使用的這些全域性資源只有乙份。乙個經典的單例模式的實現 public class singleton public st...