確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例
1. 內存中只有一個實例,減小內存開支 2. 減小對象頻繁的建立、銷燬 3. 建立資源時須要比較多的資源時減小,減小性能開銷 4. 避免對資源的多重佔用 5. 在系統設置全局訪問點,優化和共享資源訪問
1. 沒有接口,擴展困難 2. 與單一原則職責有衝突,一個類應該只實現本身的邏輯,並不須要關心它是否單例的, 是否是單例取決與環境,單例模式把 「要單例」和業務邏輯融合了(能夠用內部類持有單例的方式解決此問題)
系統要求某個類有且只有一個實例,不然就會出現「不良反應」
具體場景舉例java
生成惟一的序列號 項目中須要一個共享訪問點或共享數據
須要產生多個固定數量或有上限數量對象的模式就叫多例模式。能夠在設計系統的時候決定系統產生多少個 實例,方便進行擴展,修正單例存在的性能問題,提供響應速度
· 簡單類的單例安全
類被加載時就會被實例化一個對象
· 優勢ide
線程安全
· 缺點性能
不能被延遲加載 沒有被調用狀況,浪費系統資源
· 實現方式測試
public class SimpleHungrySingleInstance { private static final SimpleHungrySingleInstance instance = new SimpleHungrySingleInstance(); private SimpleHungrySingleInstance(){ } public static SimpleHungrySingleInstance getSingleInstance(){ return instance; } }
枚舉只能擁有私有的構造器優化
枚舉類其實是一個繼承 Enum 的一個 final 類線程
枚舉類不容許被反序列化,Enum 重寫了方法設計
靜態代碼塊中對 final 變量的值進行初始化指針
enum 類最終是一個 final classcode
/** * 利用枚舉實現單例 * */ public class ThreadSafeSingleInstanceFactoryFive { private ThreadSafeSingleInstanceFactoryFive(){ } private enum SingleFactoryEnum{ SINGLE_FACTORY_ENUM { @Override public void doSomeThing() { } }; private Cat cat = null; public void doSomeThing(){ System.out.println("cat.hashCode=" + cat.hashCode()); } SingleFactoryEnum(){ cat = new Cat(); } } public static Cat getCat(){ return SingleFactoryEnum.SINGLE_FACTORY_ENUM.cat; } public static void doSomeThing(){ SingleFactoryEnum.SINGLE_FACTORY_ENUM.doSomeThing(); }
只在須要對象時纔會生成單例對象
· 優勢
能延遲加載
· 缺點
須要本身保證線程安全
· 實現方式
synchronized 方法獲取
線程安全,鎖粒度爲Class,粒度較大,性能受影響
public class ThreadSafeSingleInstanceModelOne { private static ThreadSafeSingleInstanceModelOne threadSafeSingleInstanceModelOne = null; private ThreadSafeSingleInstanceModelOne(){ } /** * * @return */ public synchronized static ThreadSafeSingleInstanceModelOne getInstance(){ if(threadSafeSingleInstanceModelOne == null){ try { Thread.sleep(300); //模擬實例化須要的時間 } catch (InterruptedException e) { e.printStackTrace(); } threadSafeSingleInstanceModelOne = new ThreadSafeSingleInstanceModelOne(); } return threadSafeSingleInstanceModelOne; } }
synchronized 同步塊
非線程安全
public class ThreadSafeSingleInstanceModelTwo { private static ThreadSafeSingleInstanceModelTwo instance = null; public static ThreadSafeSingleInstanceModelTwo getInstance(){ if(instance == null){ // 多個線程可能會同時在這裏判true,所以屢次進入同步塊 synchronized (ThreadSafeSingleInstanceModelTwo.class){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } instance = new ThreadSafeSingleInstanceModelTwo(); } } return instance; } }
public class ThreadSafeSingleInstanceModelThree { /** * 採用Volatile 和 DCL機制 * * volatile 關鍵字做用 只能保證可見性 * 1,多個線程可見 * 2,禁止指令重排 * * 通常對象的建立步驟 分配地址 -> 初始化屬性 -> 指針指向分配地址 * * 編譯器優化致使指令重排 可能出現 * 分配地址 * -> 指針指向分配地址(沒有初始化 返回是個null對象 原始類型範圍內的值(例如int 的範圍爲-128 ~ 127 ,超事後自動轉化爲對象建立)) * -> 初始化屬性 * * * * Double Check Locking 雙檢查鎖機制(推薦) * 同步塊中不檢查的狀況可能還會屢次建立對象 * */ private volatile static ThreadSafeSingleInstanceModelThree instance = null; public static ThreadSafeSingleInstanceModelThree getInstance() { if (instance == null) { synchronized (ThreadSafeSingleInstanceModelThree.class) { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } if (instance == null) { //此處可能對象已經分配指針但沒有初始化 採用 Double Check Locking 雙檢查鎖機制 instance = new ThreadSafeSingleInstanceModelThree(); } } } return instance; } }
4.靜態內部類的實現
/** * 靜態內部類的單例 * 沒有獲取實例的時候內部類不會被初始化 */ public class ThreadSafeSingleInstanceModelFour { private static class ThreadSafeSingleInstanceModelFourInnerClass{ public static final ThreadSafeSingleInstanceModelFour instance = new ThreadSafeSingleInstanceModelFour(); } public static final ThreadSafeSingleInstanceModelFour getInstance(){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } return ThreadSafeSingleInstanceModelFourInnerClass.instance; } }
5.序列化
public class ThreadSafeSingleInstanceModelSix implements Serializable { /** * 序列化能夠保證單例的安全 * 但反序列化的過程是readObject() 會建立一個新的對象,readResolve 特性容許你用 建立的實例代替另一個實例, * 該方法忽略了被反序列化的對象,所以返回類初始化建立的那個特殊的實例 * 所以 實例的序列 化形式不該該包含任何實際的數據;全部的實例字段都應該被聲明爲 。 * 事實上, 若是依賴readResolve 進行實例控制,帶有對象引用類型的全部實例字段都必須聲明爲 transient 。 * */ private volatile static ThreadSafeSingleInstanceModelSix instance = null; //標記爲transient private transient String testName = ""; public static ThreadSafeSingleInstanceModelSix getInstance() { if (instance == null) { synchronized (ThreadSafeSingleInstanceModelSix.class) { try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } if (instance == null) { //此處可能對象已經分配指針但沒有初始化 採用 Double Check Locking 雙檢查鎖機制 instance = new ThreadSafeSingleInstanceModelSix(); } } } return instance; } private Object readResolve() { // Return the one true Elvis and let the garbage collector // take care of the Elvis impersonator. return instance; } }
佔用資源少,不須要延時加載 餓漢式 > 懶漢式
佔用資源大,須要延時加載 懶漢式 > 餓漢式
public class SimpleSluggardSingleInstanceThread extends Thread{ @Override public void run() { log.info("Thread getInstance hashCode = {}", SimpleSluggardSingleInstance.getInstance().hashCode()); } } public SimpleSluggardSingleInstanceThread newSimpleSluggardSingleInstanceThread(){ return new SimpleSluggardSingleInstanceThread(); }
TestThreads.SimpleSluggardSingleInstanceThread[] threads = new TestThreads.SimpleSluggardSingleInstanceThread[len]; for (int i = 0; i < threads.length; i++) { threads[i] = TestThreads.getThreadHandler().newSimpleSluggardSingleInstanceThread(); } for (int i = 0; i < threads.length; i++) { threads[i].start(); }