保證一個類只有一個實例, 並提供一個訪問該實例的全局節點java
1) 對惟一實例的受控訪問數據庫
2) 得到指向該實例的全局訪問節點緩存
3) 僅在首次請求單例對象時進行初始化安全
4) 違反了單一職責原則。 該模式同時解決了兩個問題(在一個方法中進行了建立類和提供類對象的操做)多線程
5) 單例模式可能掩蓋不良設計, 好比程序各組件之間相互瞭解過多等app
6) 該模式在多線程環境下須要進行特殊處理, 避免多個線程屢次建立單例對象框架
7) 單例的客戶端代碼單元測試可能會比較困難, 由於許多測試框架以基於繼承的方式建立模擬對象。 因爲單例類的構造函數是私有的, 並且絕大部分語言沒法重寫靜態方法, 因此你須要想出仔細考慮模擬單例的方法。 要麼乾脆不編寫測試代碼, 或者不使用單例模式less
Singleton_singlethread.java: 單例(單線程)ide
package singleton; /** * @author GaoMing * @date 2021/7/18 - 19:13 */ public class Singleton_singlethread { private static Singleton_singlethread instance; public String value; private Singleton_singlethread(String value) { // The following code emulates slow initialization. try { Thread.sleep(1000); } catch (InterruptedException ex) { ex.printStackTrace(); } this.value = value; } public static Singleton_singlethread getInstance(String value) { if (instance == null) { instance = new Singleton_singlethread(value); } return instance; } }
DemoSingleThread.java: 客戶端代碼函數
package singleton; /** * @author GaoMing * @date 2021/7/18 - 19:16 */ public class DemoSingleThread { public static void main(String[] args) { System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" + "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" + "RESULT:" + "\n"); Singleton_singlethread singleton = Singleton_singlethread.getInstance("FOO"); Singleton_singlethread anotherSingleton = Singleton_singlethread.getInstance("BAR"); System.out.println(singleton.value); System.out.println(anotherSingleton.value); } }
執行結果
If you see the same value, then singleton was reused (yay!) If you see different values, then 2 singletons were created (booo!!) RESULT: FOO FOO
Singleton_multithread.java: 單例(多線程安全單例)
package singleton; /** * @author GaoMing * @date 2021/7/18 - 19:12 */ public final class Singleton_multithread { private static volatile Singleton_multithread instance; public String value; private Singleton_multithread(String value) { this.value = value; } public static Singleton_multithread getInstance(String value) { // The approach taken here is called double-checked locking (DCL). It // exists to prevent race condition between multiple threads that may // attempt to get singleton instance at the same time, creating separate // instances as a result. // // It may seem that having the `result` variable here is completely // pointless. There is, however, a very important caveat when // implementing double-checked locking in Java, which is solved by // introducing this local variable. // // You can read more info DCL issues in Java here: // https://refactoring.guru/java-dcl-issue Singleton_multithread result = instance; if (result != null) { return result; } synchronized(Singleton_multithread.class) { if (instance == null) { instance = new Singleton_multithread(value); } return instance; } } }
DemoMultiThread.java: 客戶端代碼
package singleton; /** * @author GaoMing * @date 2021/7/18 - 19:30 */ public class DemoMultiThread { public static void main(String[] args) { System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" + "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" + "RESULT:" + "\n"); Thread threadFoo = new Thread(new ThreadFoo()); Thread threadBar = new Thread(new ThreadBar()); threadFoo.start(); threadBar.start(); } static class ThreadFoo implements Runnable { @Override public void run() { Singleton_multithread singleton = Singleton_multithread.getInstance("FOO"); System.out.println(singleton.value); } } static class ThreadBar implements Runnable { @Override public void run() { Singleton_multithread singleton = Singleton_multithread.getInstance("BAR"); System.out.println(singleton.value); } } }
執行結果
If you see the same value, then singleton was reused (yay!) If you see different values, then 2 singletons were created (booo!!) RESULT: BAR BAR
識別方法: 單例能夠經過返回相同緩存對象的靜態構建方法來識別。