Java中的GOF23(23中設計模式)--------- 單例模式(Singleton)

来源:http://www.cnblogs.com/liupengcheng-wangyiqi/archive/2016/08/17/5778377.html
-Advertisement-
Play Games

Java中的GOF23(23中設計模式) 單例模式(Singleton) 在Java這這門語言裡面,它的優點在於它本身的可移植性上面,而要做到可移植的話,本身就需要一個中介作為翻譯工作,以達到本地和Java的統一,但是就這點而言就相當的消耗資源,所以就Java程式員需要不斷的去優化自己的代碼。今天所 ...


Java中的GOF23(23中設計模式)--------- 單例模式(Singleton)

    在Java這這門語言裡面,它的優點在於它本身的可移植性上面,而要做到可移植的話,本身就需要一個中介作為翻譯工作,以達到本地和Java的統一,但是就這點而言就相當的消耗資源,所以就Java程式員需要不斷的去優化自己的代碼。今天所研究的單例模式就是在這樣的條件下產生的,

    所謂單例模式,就是只有一個實例,在堆裡面只有一個。假如我們的實例,就需要一個,但是會多次用到,這樣的話就會出現很尷尬的問題。

    比如:

    1. Windows的TaskManager(任務管理器)就是很典型的只需要一個實例,
    2. Windows的Recycle(回收站)在系統中,回收站只維護一個實例
    3. 在我們的項目裡面,會常常使用到讀取配置文件的類,
    4. 網站的計數器,一般也採用單例模式,否則難以實現同步
    5. 資料庫連接池設計一般也採用單例模式,因為資料庫連接是一種資料庫資源
    6. 操作系統的文件系統,因為一個操作系統只能有一個文件系統
    7. Application 也是單例模式
    8. Spring中,每個Bean預設就是單例的,這樣做的優點是Spring容器可以管理
    9. servlet編程中,每個Servlet也是單例的
    10. 在Spring MVC/struts 1 中,所使用到的控制對象也是單例的

 

    在上述裡面我們瞭解到,單例模式在我們項目中,幾乎是天天出現,所以在這裡,我們仔細研究一下,這種設計模式的怎麼實現最好(說到實現,它的實現我們大多數人只知道有兩種,而還有三種模式知道的人不是很多,以及利用反序列化,反射漏洞去強制解除單例)

 

  •   餓漢模式
    •   使用static屬性來保持對象的單例模式,但是必須在類載入的時候載入,所以沒有延遲實例化的性能
       *             而在得到實例的對象中,沒有對資源的同步鎖,所以調用效率高
       *             而使用JVM類載入器,JVM底層天然是線程安全的,
    • 優點:線程安全調用率較高
    • 缺點:不能延遲載入
       1 public class Eager_Singleton {
       2 
       3     private static Eager_Singleton singleton = new Eager_Singleton();
       4     
       5     private Eager_Singleton(){}
       6     
       7     public static Eager_Singleton newInstance(){
       8         return singleton;
       9     }
      10 }
  •   懶漢模式 
    •   依舊使用static屬性來保持對象的單例模式,但是在方法裡面new出來,當我們去調方法的時候,再去載入,就是懶人,懶得一上來就載入,但是就因為在方法裡面實例化,所以我們要在該方法上面使用鎖的概念來對他進行同步處理,如果不加鎖,那我們在A線程裡面去掉用它和在B線程裡面去調用它他就不是一個概念了
      •  優點:可以延時載入,並且線程是安全的
      • 缺點:就是方法實現了同步,所以資源的利用率比較低。
/**
 * 懶漢單例模式
 * @author 劉酸酸
 *
 */
public class Sluggard_Singleton {

    private static Sluggard_Singleton singleton = null;
    
    private Sluggard_Singleton(){}
    
    public synchronized static Sluggard_Singleton newInstance(){
        if(singleton == null){
            singleton = new Sluggard_Singleton();
        }
        return singleton;
    }
}

 

 

  • 雙重檢測式
    • 將同步塊內部下方的代碼放至到IF內部
    • 所面臨的問題:由於編譯器優化等原因JVM底層內部模型的原因,偶爾會出問題,不建議使用。

     

/**
 * 雙重檢查鎖實現單例模式
 * @author 劉酸酸
 *
 */
public class DoubleCheck_Singleton { 

  private static DoubleCheck_Singleton instance = null; 

  public static DoubleCheck_Singleton getInstance() { 
    if (instance == null) { 
      DoubleCheck_Singleton sc; 
      synchronized (DoubleCheck_Singleton .class) { 
        sc = instance; 
        if (sc == null) { 
          synchronized (DoubleCheck_Singleton .class) { 
            if(sc == null) { 
              sc = new DoubleCheck_Singleton (); 
            } 
          } 
          instance = sc; 
        } 
      } 
    } 
    return instance; 
  } 

  private DoubleCheck_Singleton () { 

  } 
    
}
  • 靜態內部類方式實現

    • 該方式是結合懶漢式和餓漢式的優點,

     

/**
 * 測試靜態內部類實現單例模式
 * 這種方式:線程安全,調用效率高,並且實現了延時載入!
 * @author 劉酸酸
 *
 */
public class StaticInnerClass{
    
    private static class StaticInnerClass{
        private static final StaticInnerClass instance = new StaticInnerClass();
    }
    
    private StaticInnerClass(){
    }
    
    //方法沒有同步,調用效率高!
    public static StaticInnerClassgetInstance(){
        return StaticInnerClass.instance;
    }
    
}

 

  • 枚舉實現
    • 在Java的JVM裡面就是一種天然的單例模式,那就是枚舉類型,如果使用枚舉類型的話會受到JVM底層的保護
      • 比如使用反序列化,和使用反射是不能打破這個原則的

    • 優點:上訴

    • 缺點:不能延遲載入

    

/**
 * 測試枚舉式實現單例模式(沒有延時載入)
 * @author 劉酸酸
 *
 */
public enum Enum_Singleton{
    
    //這個枚舉元素,本身就是單例對象!
    INSTANCE;
    
    //添加自己需要的操作!
    public void xxxxx(){
    }    
}

 

  • 如何防止反序列化,反射破環單例模式(枚舉除外)
    • 在反射中如果我們調用了私有的構造器的話,我們就會拋異常,但是會有人跳過合法檢測,這樣是可以訪問到我們的私有構造器的
import java.lang.reflect.Constructor;

/**
 * 測試反射和反序列化破解單例模式
 * @author 劉酸酸
 *
 */
public class Main{
    
    public static void main(String[] args) throws Exception {
        
        //通過反射的方式直接調用私有構造器
        Class<Singleton> clazz = (Class<Singleton>) Class.forName("com.suansuan.singleton.Singleton");
        Constructor<Singleton> c = clazz.getDeclaredConstructor(null);
        //跳過合法檢查
        c.setAccessible(true);
        Singleton s1 = c.newInstance();
        Singleton s2 = c.newInstance();
        System.out.println(s1);
        System.out.println(s2);
  }
}
    • 反序列化時,我們也不能得到一個對象,所以,下述代碼解決這兩種問題
      /**
       * 測試懶漢式單例模式(如何防止反射和反序列化漏洞)
       * @author 劉酸酸
       *
       */
      public class Singleton implements Serializable {
          //類初始化時,不初始化這個對象(延時載入,真正用的時候再創建)。
          private static Singleton instance;  
          
          private Singleton (){ //私有化構造器
              //反射時,我們作如下操作既可以規避,跳過合法檢測的非法訪問
              if(instance!=null){
                  throw new RuntimeException();
              }
          }
          
          //方法同步,調用效率低!
          public static  synchronized Singleton getInstance(){
              if(instance==null){
                  instance = new Singleton ();
              }
              return instance;
          }
          
          //反序列化時,如果定義了readResolve()則直接返回此方法指定的對象。而不需要單獨再創建新對象!
          private Object readResolve() throws ObjectStreamException {
              return instance;
          }
          
      }

       

 

總結:使用枚舉去替代餓漢式,使用靜態內部類去替代懶漢式

 

第一次寫博客,謝謝大家如果有不對的房指出來,我們共同進步,共同發展,謝謝大家

    

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 程式說明 這是一個十分可靠的程式,這個程式的查錯能力非常強悍。程式包含了文件操作,歸併排序和字元串輸入等多種技術。 程式的功能是從外部讀取一個包括int型數據的文本文件,然後將它保存到內部臨時數組,對數組進行排序後,以文本形式輸出到指定的文件上。因為是int類型的數據,沒有很嚴重的損失精度的問題。 ...
  • 該版本的Activiti運行須知: 1.JDK 6+,Eclipse最好是Kepler以上版本。 2.試驗功能都有EXPERIMENTAL標註,被標註的部分不應該視為穩定的。 有興趣的同學可以去瞭解下Activiti Explorer項目,他涵蓋了大部分Activiti的功能,還沒有Activiti ...
  • 一、手賤行為(✿◡‿◡) 在一次開發中通過xampp方式安裝了PHP環境,需要操作資料庫時通過phpmyadmin訪問MySQL,在一次資料庫操作時想起沒有設置密碼,於是直接在mysql資料庫中的user表中將root用戶的密碼設置為“123456”,關掉頁面,重啟MySQL,再次通過phpmyad ...
  • wxPython ImportError DLL load failed: ...
  • 原文鏈接:http://blog.miguelgrinberg.com/post/easy-websockets-with-flask-and-gevent 介紹部分就先不翻了 This weekend I decided to take a short vacation from my book ...
  • 在去年的時候,偶然看到hqx演算法。 一個高質量的插值放大演算法。 與雙線性插值等插值演算法相比,這個演算法放大後對人眼保護相對比較好。 沒有雙線性插值看起來模糊,固然,也抽空把演算法簡單優化了一下。 官網及代碼: https://web.archive.org/web/20131205091805/http ...
  • 變數是用於存儲數據的容器,與代數相似,可以給變數賦予某個確定的值(例如:$x=3)或者是賦予其它的變數(例如:$x=$y+$z)。變數的定義主要有以下規則: 變數以$開始,後面跟著變數的名稱; 變數名稱有數字、字母、下劃線構成,且第一個字元不能為數字; 變數名稱不能包含空格; 變數名稱區分大小寫。 ... ...
  • 一、Python安裝 在Mac系統下,系統自帶python開發環境,打開終端,輸入python,我們就可以看到當前python版本號,例如我的系統是OS X EI Caption 10.11.1,自帶的python版本是2.7。 目前python已經更新到3.6,因為python3和python2做 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...