確保一個類只有一個實例,而且自行實例化並向系統提供這個實例;提供全局訪問的方法java
常見場景:windows的任務管理器(單實例)windows
上面的getInstance方法在多線程狀況下,或致使屢次new實例,從而使用方獲得的不是同一份實例安全
代碼樣例:多線程
/** * 餓漢式單例:類加載式就啓動實例的初始化,保證使用時實例已建立完畢,從而全部適用方都獲取同一份實例 * @author clari * */ public class EagerSingleton { // 類加載時,隨即被實例化 private static EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { } public static EagerSingleton getInstance() { return instance; } }
代碼樣例性能
/** * 懶漢式單例 * 第一次使用時才建立,延遲加載,可能資源初始化耗時 * @author clari * */ public class LazySingleton { private volatile static LazySingleton instance = null; private LazySingleton() { } // 雙重檢查鎖定:同時增長volatile確保成員變量能夠對多個線程正確處理 private static LazySingleton getInstance() { if (null == instance) { synchronized (LazySingleton.class) { if (null == instance) { instance = new LazySingleton(); } } } return instance; } }
餓漢式:類加載時已實例化,不用考慮多線程訪問問題。可是無論實例最終是否會使用,都會提早實例化,可能形成資源的浪費;同時系統加載時需實例化,可能形成系統加載緩慢;spa
懶漢式:第一次使用時實例化,不提早預佔資源,必須處理好多個線程訪問的問題。實例化時可能會耗費較長時間,意味着多線程同時訪問的概率更大,須要雙重檢查致使系統性能獲得損失。線程
IoDH: Initialization on Demand Holder: 類中增長一個靜態內部類,內部類建立實例對象。code
第一次調用getInstance()方法時加載內部類,此時初始化該內部類的靜態對象instance,由Java虛擬機保證內部類初始化實例的的線程安全性,確保只初始化一次。對象
既實現延遲加載,又保證線程安全,不影響系統性能(getInstance()方法沒有任何線程綁定)。blog
public class BetterSingleton { private BetterSingleton() { } private static class HolderClass { private final static BetterSingleton instance = new BetterSingleton(); } private static BetterSingleton getInstance() { return HolderClass.instance; } public static void main(String[] args) { BetterSingleton s1, s2; s1 = BetterSingleton.getInstance(); s2 = BetterSingleton.getInstance(); System.out.println("s1 == s2: " + (s1==s2)); } }
一、沒有抽象層,擴展存在困難;
二、職責太重,必定程度違背單一職責原則,同時提供業務方法,也提供建立對象方法,將對象建立和訪問耦合一塊兒。
三、java實現了垃圾自動回收,若是實例化對象長期不適用,可能會被垃圾回收,後面再適用再次從新實例化,則可能致使共享的單例對象狀態的丟失。