單例設計模式(這一篇足夠了)

来源:https://www.cnblogs.com/xiexin2015/archive/2018/05/15/9043429.html
-Advertisement-
Play Games

單例模式真是一個老掉牙的問題了,不過我今天是要說些裡面更深點的知識,閑話少說,直接來代碼 1、餓漢式 相信這種寫法大家都知道,一開始接觸單例的時候,大家應該都是用的這種方法: 這種方式優點就是線程安全, 缺點也很明顯,就是類載入的時候,就已實例化該對象了,後面有可能用不到這個實例對象,這樣就會造成空 ...


 

  單例模式真是一個老掉牙的問題了,不過我今天是要說些裡面更深點的知識,閑話少說,直接來代碼

  1、餓漢式

   相信這種寫法大家都知道,一開始接觸單例的時候,大家應該都是用的這種方法:

package com.hd.single;

public class Singleton {

    private Singleton(){}
    private static Singleton instance = new Singleton();

    public static Singleton getInstance(){
        return instance;
    }
}

  這種方式優點就是線程安全, 缺點也很明顯,就是類載入的時候,就已實例化該對象了,後面有可能用不到這個實例對象,這樣就會造成空間浪費。因此就有了懶載入方式。

  2、懶漢式

  1)懶漢式L1

package com.hd.single;

public class Singleton2 {

    private Singleton2(){}
    private static Singleton2 instance;

    public static Singleton2 getInstance(){
        if(instance == null)        //1
            instance = new Singleton2();  //2
        return instance;
    }

}

  這種懶漢式的優點和缺點也很明顯,優點是按需載入,節省空間, 缺點是線程不安全。簡單說就是,有可能線程A執行到“1”處時,阻塞住了,線程B搶到CPU,進來執行並實例化對象,然後線程A醒來後,繼續往下執行,這樣線程A和B取到的就是不同的對象。因此,又有了線程安全的版本。

package com.hd.single;

public class Singleton2 {

    private Singleton2(){}
    private static Singleton2 instance;

    public static synchronized Singleton2 getInstance(){
        if(instance == null)
            instance = new Singleton2();
        return instance;
    }
}

  但是加了synchronized 之後會造成線程阻塞,影響性能。於是又提出了雙檢鎖的方式

 1 package com.hd.single;
 2 
 3 public class Singleton2 {
 4 
 5     private Singleton2(){}
 6     private static Singleton2 instance;
 7 
 8     public static Singleton2 getInstance(){
 9         if(instance == null){
10             synchronized (Singleton2.class){
11                 if(instance == null){
12                     instance = new Singleton2();
13                 }
14             }
15         }
16         return instance;
17     }
18 }

  看似雙檢鎖的方式很完美,既解決了線程安全的問題,又兼顧了性能問題: 線程先判斷instance變數是否為空,如果不為空,則直接返回。否則進入同步塊去實例化對象。但事實這是一個錯誤的優化!

  重點就是第12行代碼(instance = new Singleton2();), 它創建了一個對象。這一行代碼可以分解為如下的3行代碼:

memory = allocate();         //1:分配對象的記憶體空間
ctorInstance(memory);        //2:初始化對象
instance = memory;           //3:設置instance指向剛分配的記憶體地址

  上面2和3這兩步之間,有可能會被重排序,2和3重排序之後的執行時序如下:

memory = allocate();         //1:分配對象的記憶體空間
instance = memory;           //3:設置instance指向剛分配的記憶體地址
                           //註意此時對象還沒有被初始化
ctorInstance(memory);        //2:初始化對象
                                    

  因此如果有線程A執行到3時,此時instance變數確實不為空,然後線程B判斷instance不為空後返回,那麼這是線程B 取到的就是一個空的對象。顯示這樣是有問題的,因此為了防止出現這個問題,需要使用volatile變數,來禁止指令重排序。

  2)懶漢式 L2(基於volatile的解決方案)

package com.hd.single;

public class Singleton {

    private Singleton(){}
    private volatile static Singleton instance;

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

  我們除了通過volatile的方式來禁止指令重排序,還可以提供另外一種思路:允許2和3重排序,但不允許其它線程“看到”這個重排序。 前面正是因為線程B看到了重排序,發現instance變數不為空,所以才造成其取到空的對象。

  3)懶漢式L3(基於靜態內部類的方案)

package com.hd.single;
public class LazySingleton2 {
    private LazySingleton2() {
    }
    static class SingletonHolder {
        private static final LazySingleton2 instance = new LazySingleton2();
    }
    public static LazySingleton2 getInstance() {
        return SingletonHolder.instance;
    }
}

  因為 在載入外部類時,其內部類不會同時被載入。只有調用 getInstance方法的時候,內部類才會去被載入,且只載入一次,不存在併發問題,因此是線程安全的。

  另外,在getInstance()方法中沒有使用synchronized關鍵字,因此沒有造成多餘的性能損耗。

 

  本文給出了多個版本的單例模式,供我們在項目中使用。一般用L2,L3就基本夠用。

 


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

-Advertisement-
Play Games
更多相關文章
  • CSS3 transform變換 1、translate(x,y) 設置盒子位移2、scale(x,y) 設置盒子縮放3、rotate(deg) 設置盒子旋轉4、skew(x-angle,y-angle) 設置盒子斜切5、perspective 設置透視距離6、transform-style fla ...
  • CSS權重 CSS權重指的是樣式的優先順序,有兩條或多條樣式作用於一個元素,權重高的那條樣式對元素起作用,權重相同的,後寫的樣式會覆蓋前面寫的樣式。 權重的等級 可以把樣式的應用方式分為幾個等級,按照等級來計算權重 1、!important,加在樣式屬性值後,權重值為 100002、內聯樣式,如:st ...
  • 詳情請 咨詢 QQ 759104513 精品新增,持續中.... 192、PHP進階:面向對象及TP5框架初識-慕課網職業路徑 191、0961、手把手帶你入坑H5與小程式直播開發 190、SpringBoot2.0不容錯過的新特性 WebFlux響應式編程 189、Vue2.5開發去哪兒網App ...
  • 定位 關於定位 我們可以使用css的position屬性來設置元素的定位類型,postion的設置項如下: relative 生成相對定位元素,元素所占據的文檔流的位置不變,元素本身相對文檔流的位置進行偏移 absolute 生成絕對定位元素,元素脫離文檔流,不占據文檔流的位置,可以理解為漂浮在文檔 ...
  • css元素溢出 當子元素的尺寸超過父元素的尺寸時,需要設置父元素顯示溢出的子元素的方式,設置的方法是通過overflow屬性來設置。 overflow的設置項: 1、visible 預設值。內容不會被修剪,會呈現在元素框之外。2、hidden 內容會被修剪,並且其餘內容是不可見的,此屬性還有清除浮動 ...
  • json數據作為和後臺交互的良好交互方式,這裡介紹下前端怎麼封裝成json數據給到後臺。 示例代碼: (1)封裝成json數據 最終結果為:{"id":0,"name":"張三","job":"學生"} (2)封裝成json數組 最終結果為:[{"id":0,"name":"張三","job":"學 ...
  • 前言 ​最近,被推送了不少秒殺架構的文章,忙裡偷閑自己也總結了一下互聯網平臺秒殺架構設計,當然也借鑒了不少同學的思路。俗話說,脫離案例講架構都是耍流氓,最終使用SpringBoot模擬實現了部分秒殺場景,同時跟大家分享交流一下。 秒殺場景 秒殺場景無非就是多個用戶在同時搶購一件或者多件商品,專用辭彙 ...
  • 上一篇: "ELK 架構之 Elasticsearch 和 Kibana 安裝配置" 閱讀目錄: 1. 環境準備 2. 安裝 Logstash 3. 配置 Logstash 4. Logstash 採集的日誌數據,在 Kibana 中顯示 5. 安裝配置 Filebeat 6. Filebeat 採 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...