初窺設計模式——單例模式

来源:https://www.cnblogs.com/WangYunShuaiBaoLe/archive/2018/01/10/8257221.html
-Advertisement-
Play Games

資料借鑒:http://cantellow.iteye.com/blog/838473 簡單介紹: 單例模式是一種經常用到的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中應用該模式的類只有一個實例。即一個類只有一個實例 定義: 一個類有且只有一個實例,並且自行 ...


資料借鑒:http://cantellow.iteye.com/blog/838473

簡單介紹:   單例模式是一種經常用到的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中應用該模式的類只有一個實例。即一個類只有一個實例 定義:   一個類有且只有一個實例,並且自行實例化向整個系統提供。 特點:        1、單例類只能有一個實例。   2、單例類必須自己創建自己的唯一實例。   3、單例類必須給所有其他對象提供這一實例。 實現方式:   一般來說,我們有以下幾個必要的操作:     1、私有化構造方法;     2、final類(定義為不可繼承,這點書上沒有提到,暫時還在研究)     3、將類的實例對象定義為一個私有的屬性(不限製為成員變數)     4、通過getInstance()方法獲取實例,若私有的實例屬性對象引用不為空則返回,否則實例化該屬性並返回   這裡先介紹四種實現方式       1、餓漢模式     2、懶漢模式     3、雙重驗證     4、靜態內部類模式   先看第一種方式,餓漢模式顧名思義,迫不及待的想要吃(初始化實例),在類中定義一個私有靜態本類的實例化對象,在類載入的過程就進行此對象的實例化,之後的對此類實例的調用都是調用此實例。 代碼如下:
public class Singleton2 {

    private static Singleton2 singleton2= new Singleton2();

    private Singleton2(){}

    public static Singleton2 getInstance() {
        return singleton2;
    }

    public static String getStr() {
        return "Create String type Object";
    }
}
餓漢模式是較為簡單的實現方式,同樣也是較為常用的方式。但他有著一定的缺陷:雖然在單例模式中大多都只調用getInstance()方法,但不排除有其他的方式導致類載入,比如如果類中getStr()這種與類的實例無關的方法如果被調用,就會觸發類載入,從而對靜態成員進行初始化,但是此類有可能並不需要實例化,這樣在某種程度上會造成一定的資源浪費。也就無法達到lazy loading的效果。   這就引入了懶漢模式   懶漢模式:只有在第一此調用類的實例對象時才會初始化類的實例,從而實現延遲載入 代碼如下
public class Singleton3 {

    private static Singleton3 singleton2 = null;

    private Singleton3(){
        Tools.println("類實例化");
    }

    public static synchronized Singleton3 getInstance(){
        if(singleton2 == null)
            singleton2 = new Singleton3();
        return singleton2;
    }

    public static void CreateString(){
        Tools.print("Create String in Singleton3");
    }
}
懶漢模式通過getInstance()方法創建實例,這樣只有在使用到實例的時候才會初始化實例對象,實現了延遲載入,但是這種模式會出現線程同步問題:一個線程調用了getInstace()方法,判斷為空後進行實例的創建,此時又有了一個線程調用了getInstance()方法,但此刻第一個線程還沒有完成實例化的操作,故此線程也會實例化一個對象。所以我們需要為getInstance()方法加上同步關鍵字synchronized 。 那麼問題來了,我們使用延遲載入就是為了提升系統性能,而引入了同步關鍵字則會大大影響多線程情況下的性能,所以此方式也有這很大的缺陷。   下麵就引入了雙重檢測方式   雙重檢測方式:通過雙重檢測的方式完成延遲載入 代碼如下:
class Singleton1 {

    private Singleton1() {
    }

    public static Singleton1 instance = null;

    public static Singleton1 getInstance() {
        if (instance == null) {
            synchronized (Singleton1.class) {
                if (instance == null) {
                    instance = new Singleton1();
                }
            }
        }
        return instance;
    }
}
可以看到,首先判斷實例對象是否為空,如果判斷通過再進行同步操作。 這種方式是解決了懶漢模式的效率問題,但同時也有一些問題,第一次載入時反應不快,由於java記憶體模型一些原因偶爾失敗。失敗原因可以詳見http://blog.csdn.net/chenchaofuck1/article/details/51702129   接下來引入一種已經較為完善並且使用較多的一種實現方式:靜態內部類實現 代碼如下: public class Singleton4 { private Singleton4(){} static class SingletonHolder { private static Singleton4 singleton = new Singleton4(); } public static Singleton4 getInstance(){ return SingletonHolder.singleton; } } 此方式利用了:靜態內部類並不會在外部類類載入的時候也進行類載入,而是在它自身第一次被使用時進行類載入,並且jvm的類載入過程是對線程非常友好的,所以我們不需要擔心同步問題。
public class Singleton4 {

    private Singleton4(){}

    static class SingletonHolder {
        private static Singleton4 singleton = new Singleton4();
    }

    public static Singleton4 getInstance(){
        return SingletonHolder.singleton;
    }
}
  上述方法都是基本上實現了單例模式,但是依然有兩個問題需要註意: 1:如果單例由不同的類裝載器註入,那邊有可能存在有多個單例類的實例。假如不是遠端存取,假如一些servlet容器對每個servlet使用不同的類裝載器,他們就會有個字的單例類的實例。 2:如果單例類實現了java.io.Serializable介面,那麼此類的實例就可以被序列化和複原,如果序列化一個對象,然後複原多個此對象,就會出現多個單例類的實例。 關於此問題可以參照此文章:http://blog.csdn.net/fg2006/article/details/6409423   第一個問題的解決方法:
private static Class getClass(String classname)      
                                         throws ClassNotFoundException {     
      ClassLoader classLoader = Thread.currentThread().getContextClassLoader();     
      
      if(classLoader == null)     
         classLoader = Singleton.class.getClassLoader();     
      
      return (classLoader.loadClass(classname));     
   }     
}
第二個問題的解決方法:
public class Singleton implements java.io.Serializable {     
   public static Singleton INSTANCE = new Singleton();     
      
   protected Singleton() {     
        
   }     
   private Object readResolve() {     
            return INSTANCE;     
      }    
}  
  這兩種方法是我從其他的博客上看來的,現在還在瞭解中。。。     應用場景: 1. Windows的Task Manager(任務管理器)就是很典型的單例模式(這個很熟悉吧),想想看,是不是呢,你能打開兩個windows task manager嗎? 不信你自己試試看哦~  2. windows的Recycle Bin(回收站)也是典型的單例應用。在整個系統運行過程中,回收站一直維護著僅有的一個實例。 3. 網站的計數器,一般也是採用單例模式實現,否則難以同步。 4. 應用程式的日誌應用,一般都何用單例模式實現,這一般是由於共用的日誌文件一直處於打開狀態,因為只能有一個實例去操作,否則內容不好追加。 5. Web應用的配置對象的讀取,一般也應用單例模式,這個是由於配置文件是共用的資源。 6. 資料庫連接池的設計一般也是採用單例模式,因為資料庫連接是一種資料庫資源。資料庫軟體系統中使用資料庫連接池,主要是節省打開或者關閉資料庫連接所引起的效率損耗,這種效率上的損耗還是非常昂貴的,因為何用單例模式來維護,就可以大大降低這種損耗。 7. 多線程的線程池的設計一般也是採用單例模式,這是由於線程池要方便對池中的線程進行控制。 8. 操作系統的文件系統,也是大的單例模式實現的具體例子,一個操作系統只能有一個文件系統。 9. HttpApplication 也是單位例的典型應用。熟悉ASP.Net(IIS)的整個請求生命周期的人應該知道HttpApplication也是單例模式,所有的HttpModule都共用一個HttpApplication實例.   總結以上,不難看出:   單例模式應用的場景一般發現在以下條件下:   (1)資源共用的情況下,避免由於資源操作時導致的性能或損耗等。如上述中的日誌文件,應用配置。   (2)控制資源的情況下,方便資源之間的互相通信。如線程池等。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1 var list= $('input:radio[name="name"]:checked').val(); //選擇input中單選name為“name”的並且是選中狀態的 index =$(document).data('index'); //把參數存入document中保存起來併在下一次中... ...
  • nowrap="nowrap" //用於列表中td不許換行 maxlength="100" //用於輸入框的長度限制 colspan="2" //用於td橫向合併 rowspan="2" //用於td縱向合併 style="text-align: center;" //用於字體居中 style="d... ...
  • 表象不同,get把提交的數據url可以看到,post看不到 原理不同,get 是拼接 url, post 是放入http 請求體中 提交數據量不同,get最多提交1k數據,瀏覽器的限制。post理論上無限制,受伺服器限制 get提交的數據在瀏覽器歷史記錄中,安全性不好 場景不同,get 重在 "要" ...
  • 來自:SangSir 鏈接:https://segmentfault.com/a/1190000012673854 原文:https://www.sitepoint.com/shorthand-javascript-techniques/ 1.三元操作符 當想寫 if...else 語句時,使用三元 ...
  • 1、網址 https://mydevice.io/ 2、使用 在mydevice.io上有常見智能手機,PC電腦的尺寸。 ...
  • 集群:高可用,備份,數據可分片 需要運行4個tomcat 1、tomcat埠號(預設占用8005,8009,8080三個埠) tomcat服務 占用埠 tomcat1 6005、6060、6009 tomcat2 7005、7070、7009 tomcat3 8005、8080、8009 to ...
  • 一,idea項目原結構 ics.credit src mian java com.pingan.credit resources config 一系列的配置文件 webapp WEB-INF lib web.xml error.jsp index.jsp 二,idea項目打包後結構 target c ...
  • 一、寫在前面 應用分層這件事情看起來很簡單,但每個程式員都有自己的一套,哪怕是初學者。如何讓一家公司的幾百個應用採用統一的分層結構,並得到大部分程式員的認同呢?這可不是件簡單的事情,接下來以我們真實案例與大家一起探討,先問大家兩個技術問題: 服務的調用代碼你覺得放到哪一層好呢? A 表現層 B 業務 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...