單例模式應用於一個類只有一個實例的情況,並且為其實例提供一個全局的訪問點。
特點:
1.一個類只有一個實例
2.自己創建這個實例
3.整個系統只能用這個實例
應用場景
外部資源:每台計算機有若干個打印機,但只能有一個PrinterSpooler,以避免兩個打印作業同時輸出到打印機。
內部資源:大多數軟件都有一個(或多個)屬性文件存放系統配置,這樣的系統應該有一個對象管理這些屬性文件。
實現方式
1.餓漢式:單例實例在類裝載時就構建,急切初始化。(預先加載法)
/** * 餓漢式(推薦) * */ public class Singleton1 { private Singleton1() { } public static Singleton1 instance = new Singleton1(); public Singleton1 getInstance() { return instance; } }
優點 | 1.線程安全 2.在類加載的同時已經創建好一個靜態對象,調用時反應速度快 |
缺點 | 資源效率不高,可能getInstance()永遠不會執行到,但執行該類的其他靜態方法或者加載了該類(class.forName),那么這個實例仍然初始化 |
2.懶漢式:單例實例在第一次被使用時構建,延遲初始化。
class Singleton2 { private Singleton2() { } public static Singleton2 instance = null; public static Singleton2 getInstance() { if (instance == null) {
//多個線程判斷instance都為null時,在執行new操作時多線程會出現重復情況 instance = new Singleton2(); } return instance; } }
懶漢式在單個線程中沒有問題,但在多線程就可能會出現兩個或多個Singleton2實例情況,
雖然后面實例化的Singleton2會覆蓋前面實例化的Singleton2,但最好避免這樣的情況。
改進方式就是加鎖synchornized
class Singleton3 { private Singleton3() { } public static Singleton3 instance = null; public static synchronized Singleton3 getInstance() { if (instance == null) { instance = new Singleton3(); } return instance; } }
優點 | 資源利用率高,不執行getInstance()就不會被實例,可以執行該類的其他靜態方法 |
缺點 | 第一次加載時不夠快,多線程使用不必要的同步開銷大 |
3.雙重檢測
class Singleton4 { private Singleton4() { } public static Singleton4 instance = null; public static Singleton4 getInstance() { if (instance == null) { synchronized (Singleton4.class) { if (instance == null) { instance = new Singleton4(); } } } return instance; } }
優點 | 資源利用率高,不執行getInstance()就不被實例,可以執行該類其他靜態方法 |
缺點 | 第一次加載時反應不快,由於java內存模型一些原因偶爾失敗 |
4.靜態內部類
class Singleton5 { private Singleton5() { } private static class SingletonHelp { static Singleton5 instance = new Singleton5(); } public static Singleton5 getInstance() { return SingletonHelp.instance; } }
優點 | 資源利用率高,不執行getInstance()不被實例,可以執行該類其他靜態方法 |
缺點 | 第一次加載時反應不夠快 |
總結:一般采用餓漢式(1),若對資源十分在意可以采用靜態內部類(4),不建議采用懶漢式及雙重檢測(2、3)