使用懶漢式加載。 最終能夠作到 線程安全,延遲加載,效率高的特色。java
package oneDay; /** * 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點 * 1:構造方法私有化 * 2:聲明一個本類對象 * 3:給外部提供一個靜態方法獲取對象實例 * <p> * <p> * 單例設計模式的存在是爲了什麼? * 1:在設計一些工具類的時候,不須要屬性這些東西,只須要方法就能夠,因此就不摻和對象,只用單例就能夠. * 2:工具類可能會被頻繁調用. * 目的是爲了節省重複建立對象所帶來的內存消耗.從而提升效率. * <p> * 能不能使用構造方法私有化再加上static 來替代單例? 不能, 構造方法 不能靜態化. * <p> * <p> * 在類被加載的時候 由於類中的實例是有 static修飾的,因此當時的實例已經建立好了. * 而後繼續getIntance的時候 獲得的就是 同一個對象. */ public class singleCase { public static void main(String[] args) { } } // 餓漢式 : 在類被加載後,對象被建立,到程序結束以後釋放. class Singleton1 { private Singleton1() { } private static Singleton1 s = new Singleton1(); public static Singleton1 getInstance() { return s; } public void print() { System.out.println("測試方法1!"); } } // 懶漢式 : 在第一次調用getInstance方法時,對象被建立,到程序結束後釋放. // 在多線程訪問的時候 可能會由於生命週期的問題 而出現程序崩潰錯誤. // 可能出現 第一個線程進入 getInstance的時候, 發現s爲空 , 在沒有 聲明實例的時候, 第二個進程也發現了 s 爲空. 這個時候 實例就變了. // 解決方法: // 1: 將getInstance加上線程鎖, 可是這樣的話就是 串行執行了 . 效率的良心大大滴壞了. // 2: 還有一種說話 是給 s = new Singleton2(); 加上同步代碼塊, 可是這樣顯然無法解決 實例變化的問題. 是個扯淡的方法. class Singleton2 { private Singleton2() { } private static Singleton2 s; public static Singleton2 getInstance() { if (s == null) s = new Singleton2(); return s; } public void print() { System.out.println("測試方法2!"); } } // 3: 結合第二種方法, 實現第三種方法 . 加上同步代碼塊減小鎖影響的顆粒大小, 而且避免第二種方法的問題. 就是在同步代碼塊中 再次判斷是否爲空. // 雙重加鎖法. 可是這樣還可能會存在問題. 由於牽扯到 JVM實現 s = new Singleton3(); 的指令順序問題 . // 其指令大體分爲如下三步: 1 申請一塊內存空間用於存放實例內容 2 在該空間實例化對象 3 將該內存地址富裕s // 底層執行的時候 不必定是按照123 執行的, 有多是132 (底層代碼速度優化方案.). 這樣的話 在沒有實例化對象的時候 , s不爲null , 這樣另外一個線程發現s 不爲空, 可是拿到的是空的s , 這個時候程序就炸了. class Singleton3 { private Singleton3() { } private static Singleton3 s; public static Singleton3 getInstance() { if (s == null) synchronized (Singleton3.class) { /* 第三種方案對 對二種方法的改進 */ if (s == null) { s = new Singleton3(); } } return s; } public void print() { System.out.println("測試方法2!"); } } // 4: 爲了解決第三種方案的缺陷, 咱們須要禁止代碼重排. 由此而生第四種方案, 這個應該是最完美的方案了. class Singleton4 { private Singleton4() { } /* 第四種方案對第三種的優化 */ private static volatile Singleton4 s; public static Singleton4 getInstance() { if (s == null) synchronized (Singleton4.class) { /* 第三種方案對 對二種方法的改進 */ if (s == null) { s = new Singleton4(); } } return s; } public void print() { System.out.println("測試方法2!"); } }
使用餓漢式配合類裝載機制,也能夠實現懶加載和線程安全,以及高效。設計模式
public class Singleton { private Singleton() {} private static class SingletonInstance { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonInstance.INSTANCE; } }
類加載器加載類的時候,會將靜態屬性直接初始化。 經過這裏類加載器的特性, 咱們能夠作到線程安全。 經過內部類的方式,實現懶加載。安全