A5) Singleton(單態(tài)模式) 定義:保證一個類只存在一個實例,并提供一個全局訪問的指針。 這個也是非常常見的模式,可以說很難在一個項目中不使用這個模式。對于全局變量來說,唯一和同步是至關重要的,一般來說以下面的這種方式來實現(xiàn)。 public class Singleton { private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } } 第一行必須用private的構造函數(shù),這樣才能防止別的class生成Singleton的實例,而第二行的static定義讓變量instance在所有Singleton實例中是唯一的(當然,這個例子實際上只有一個實例),那么每次通過getInstance()得到的變量instance就是Singleton的唯一實例。還有一種方法,如下: public class Singleton { private Singleton(){} private static Singleton instance = null; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 這種方法叫做lazy initialization技術,不過關于這種技術的爭議很多,牽涉到double-checked locking(DCL)問題。關于這個問題,稍微解釋一下,具體我也不是太明確,有興趣可以另外研究。編譯器在編譯執(zhí)行命令的時候,由于會使用代碼優(yōu)化,在synchronized段中的代碼就有可能會被提前執(zhí)行以加快代碼效率。這個時候,也就是instance = new Singleton();這部分語句可能被預先優(yōu)化執(zhí)行,那么它的唯一性也就不能保證了。雖然還只是在理論上推論這個結果,并沒有用事實來驗證這一說法,現(xiàn)在也沒發(fā)現(xiàn)這個方法造成的不良后果,但是,我覺得還是推薦第一種方法,簡單而容易理解。
注:感謝rwyx的指點,因為以前理解有偏差,所以將上面部分刪除后重新改寫。 這種方法叫做lazy initialization技術,使用了synchronized關鍵字,不過這種方法的系統(tǒng)開銷比較大,所以還是推薦地一種方法,簡單而且效率高,最好在定義時追加final關鍵字。 關于Singleton,在C++/C#等語言中會用到一種叫做double-checked的技術,目的是為了解決lazy initializtion技術中同步代碼效率低的問題。具體實現(xiàn)如下: public static Singleton getInstance() { if (instance == null) { synchronized { if (instance == null) {instance = new Singleton();} } } return instance; } 即在同步前做一次判斷,這樣只有第一次時會進入同步段,這樣效率也很高。不過這種方法在java中卻是錯誤的。因為java語言規(guī)范和C++/C# 等不同,是一個非常靈活的規(guī)范。java編譯器可以自由地重排變量的初始化和訪問順序,以提高運行時效率;同時java中的變量訪問是可以被自動緩存到寄存器的,這也導致潛在的JIT 編譯器相關的依賴性錯誤。每個編譯器可能有不同的實現(xiàn)方法,同樣的代碼在不同編譯器和執(zhí)行環(huán)境下可能有不同的表現(xiàn)。解決的辦法有很多,使用線程局部存儲(ThreadLocal)來保存instance變量,或者使用volatile關鍵字來定義instance,強制java編譯器不進行優(yōu)化。DCL參考資料: http://www./User8/flier_lu/blog/1620823.html
參考: 1、 http://www./designpatterns/singleton.htm(中文、java實例) 2、 http://www./Patterns/PatternSingleton.aspx(英文、C#實例、UML) 3、 http://www./tech/DesignPattern/Singleton.html(日文、java實例、UML)推薦
|