摘要:總結單例是運用頻率很高的模式,因為客戶端沒有高并發的情況,選擇哪種方式并不會有太大的影響,出于效率考慮,推薦使用和靜態內部類實現單例模式。
單例模式介紹
單例模式是應用最廣的模式之一,也可能是很多人唯一會使用的設計模式。在應用單例模式時,單例對象的類必須保證只用一個實例存在。許多時候整個系統只需要一個全局對象,這樣有利于我么能協調整個系統整體的行為。單例模式的使用場景
確保某個類有且只有一個對象的場景,避免創建多個對象消耗過多的資源,或者某個對象只應該有且只有一個。例如,創建一個對象需要消耗的資源過多,如要訪問IO和數據庫的資源,需要頻繁進行創建和銷毀的對象,這時候就需要考慮使用單例模式。單例的實現方式 餓漢式
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }懶漢式
public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
getInstance()方法中添加了synchronized關鍵字,也就是getInstance是一個同步方法,在多線程情況下保證單例的對象唯一性的手段。但是會發現個問題即使instance已經被初始化,每次調用getInstance方法都會進行同步,這樣會消耗不必要的資源,這也是懶漢式的最大的文問題。最后總結下:Double Check Lock(DCL)實現單例
優點:單例只在使用時才被初始化,一定程度上節約了資源。
缺點:第一次加載時需要進行實例化,反應稍慢,最大問題是每次調用getInstance都會進行同步,造成不必要的同步開銷,這種模式一般不建議使用。
public class Singleton { private static Singleton instance = null; private Singleton() { } public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
getInstance方法中對instance進行了兩次判空,第一層判斷主要是避免不必要的同步,第二層判斷是為了在null放的情況下創建實例。由于Java編譯器允許處理器亂序執行,在JDK1.5之前JMM(Java內存模型)會偶爾失敗,會發生DCL失效問題。JDK1.5之后,SUN調整了JVM,又優化了volatile關鍵字,只要將instance定義改成 private volatile static Singleton instance = null就可以保證每次都是從主內存讀取,就可以使用DCL的寫法來完成單例。靜態內部類單例模式
優點資源利用率高,既能在需要時才初始化單例,又能保證線程安全,且單例對象初始化后調用getInstance不進行同步,效率高。
缺點第一次加載反應稍慢,也由于JMM的原因偶爾會失敗。在高并發環境下也有一定缺陷,雖然發生的概率較小。
DCL模式是使用最多的單例模式實現方式,除非代碼在并發場景比較復雜或者JDK1.6以下版本使用,否則,這種方式基本都能滿足需求。
public class Singleton { private Singleton() { } public static Singleton getInstance() { return SingletonHolder.instance; } private static class SingletonHolder { private static Singleton instance = new Singleton(); } }
DCL模式雖然在一定程度解決了資源消耗、多余的同步、線程安全等問題,但是,它還是在某種情況下會出現失效問題。枚舉單例
第一次加載Singleton類并不會初始化instance,只有在第一次調用getInstance()方法時instance才被初始化,因此第一次調用getInstance方法會導致虛擬機加載SingletonHolder類,這種方法不僅能保證線程安全,也能保證單例對象的唯一性,同時也延遲了單例的實例化,所以這是推薦使用的單例模式。
public enum SingletonEnum { INSTANCE; public void doSomething() { System.out.println("do something"); } }
優點:簡單容器實現單例
枚舉在java中與普通類一樣,不僅能有字段,還能夠有自己的方法。重要的是枚舉實例的創建是線程安全的,并且在任何情況下它都是一個單例。
public class SingletonManager { private static MapobjMap = new HashMap (); public static void regsiterService(String key, Object instance) { if (!objMap.containsKey(key)) { objMap.put(key, instance); } } public static Object getService(String key) { return objMap.get(key); } }
將多種單例注入一個統一的管理類,使用時根據key獲取對象對應類型的對象。總結
這種方法是使得我們可以管理多種類型的單例,在使用過程中可以通過統一的接口進行操作,降低了使用成本,也對用戶應藏了具體實現,降低了耦合。
單例是運用頻率很高的模式,因為客戶端沒有高并發的情況,選擇哪種方式并不會有太大的影響,出于效率考慮,推薦使用DCL和靜態內部類實現單例模式。
單例的優點由于單例模式只存在一個實例,減少了內存開銷,特別是一個對象需要頻繁的創建、銷毀時,而且創建或銷毀時性能無法優化,單例模式的優勢就十分明顯。
由于單例模式只生成一個實例,減少了系統的性能開銷,當一個對象的產生需要比較多的資源時,可以通過應用啟動時直接產生一個單例對象。然后用永久駐留內存的方式來解決。
單例模式可以避免對資源的多重占用,比如文件的讀寫操作。
單例模式可以在系統中設置安全的訪問點,優化和共享資源訪問,比如可以設計一個單例類,負責所有數據表的映射處理。
單例的缺點單例模式一般沒有接口,擴展困難。
單例對象如果持有Context,容易引發內存泄漏,此時需要傳遞給單例對象的Context最好是Application Context。
微信公眾號:碼農修煉之道
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/71431.html
摘要:所以,在版本前,雙重檢查鎖形式的單例模式是無法保證線程安全的。 單例模式可能是代碼最少的模式了,但是少不一定意味著簡單,想要用好、用對單例模式,還真得費一番腦筋。本文對Java中常見的單例模式寫法做了一個總結,如有錯漏之處,懇請讀者指正。 餓漢法 顧名思義,餓漢法就是在第一次引用該類的時候就創建對象實例,而不管實際是否需要創建。代碼如下: public class Singleton...
摘要:即便如此,出于效率考慮,推薦使用雙重校驗鎖和靜態內部類單例模式。 概述 單例模式是應用最廣的模式之一,在應用這個模式時,單例對象的類必須保證只有一個實例存在。許多時候整個系統只需要擁有一個全局對象,這樣有利于我們協調系統整體的行為。如在一個應用中,應該只有一個ImageLoader實例,這個ImageLoader中又含有線程池、緩存系統、網絡請求等,很消耗資源。因此不應該讓它構造多個實...
摘要:一基礎接口的意義百度規范擴展回調抽象類的意義想不想通過一線互聯網公司面試文檔整理為電子書掘金簡介谷歌求職記我花了八個月準備谷歌面試掘金原文鏈接翻譯者 【面試寶典】從對象深入分析 Java 中實例變量和類變量的區別 - 掘金原創文章,轉載請務必保留原出處為:http://www.54tianzhisheng.cn/... , 歡迎訪問我的站點,閱讀更多有深度的文章。 實例變量 和 類變量...
閱讀 1344·2023-04-26 00:35
閱讀 2714·2023-04-25 18:32
閱讀 3344·2021-11-24 11:14
閱讀 770·2021-11-22 15:24
閱讀 1417·2021-11-18 10:07
閱讀 6466·2021-09-22 10:57
閱讀 2773·2021-09-07 09:58
閱讀 3565·2019-08-30 15:54