設計模式之單列模式

来源:http://www.cnblogs.com/seven12587/archive/2017/07/23/7226107.html
-Advertisement-
Play Games

設計模式之單列模式 1,何為單列模式? 即singleton 在某個類採用了單列模式之後 其只能有一個實列對象 ,並且這個實列對象只能有內部自己創建並提供給外部的調用。 2.實現單列模式的方法 分為 :餓漢式 ,懶漢式 下麵為餓漢式實現代碼: 餓漢式 通過創建一個靜態成員變數 在類載入的時候直接創建 ...


設計模式之單列模式

 

1,何為單列模式?

即singleton 在某個類採用了單列模式之後  其只能有一個實列對象 ,並且這個實列對象只能有內部自己創建並提供給外部的調用。

 

2.實現單列模式的方法

分為 :餓漢式懶漢式

下麵為餓漢式實現代碼:

public calss Singleton1{

    //將構造函數私有化     防止外部通過new來創建對象
    private Singleton1(){
}

   //創建一個私有靜態變數並直接初始化   類載入的時候直接創建對象
   private  static  Singleton1 single = new Singleton();

  //提供一個public方法 來讓外部調用 返回已構建的私有single

  public static Singleton1 getInstance(){
     
     return single;
    
}
}

餓漢式 通過創建一個靜態成員變數 在類載入的時候直接創建 該類的對象,所以其天生就是線程安全的。但是缺點在於 無論其是否被使用 記憶體已經為其分配好記憶體空間,所以其缺點就是對於有記憶體要求的餓漢式比較消耗記憶體。

 

懶漢式具體實現:

public class Singleton2{


     //私有化構造方法
    private Singleton2(){
}

   // 定義靜態私有成員變數 但不初始化 

   private static Singleton2 single = null;

  //提供public方法給外部用來獲取實列對象

  public static Singleton2 (){

    if(single==null){

    single = new Singleton2();

}

    return single  


}




}
View Code

這是懶漢式的基本實現方式,但其對於多線程是不安全的,因為當兩個線程同時進入getInstance方法時 線上程1經過single==null判斷後 ,對single進行初始化而並未完成初始化,線程2進入single==null判斷 由於線程1還未完成初始化 所以此時的single線上程2看來仍然是null,所以線程2也進入了對single進行初始化的代碼段,從而出現了兩個single對象  ,這與單列模式的要求是不符的,所以為了達到線程安全 下麵給出了三種方法,其中第三種方法在某些對單列模式的介紹中 單一分離了出來,但我認為其仍然屬於懶漢式,因為在類的載入過程中該類的對象並未被創建,同樣是在使用的時候才被創建。

1.通過synchronized同步化 實現線程安全

 

public calss Singleton3{

    //將構造函數私有化     防止外部通過new來創建對象
    private Singleton3(){
}

   //創建一個私有靜態變數  占不創建對象
   private  static  Singleton3 single = null;

  //提供一個public方法 並加上synchronized關鍵字 同步化來讓外部調用 返回已構建的私有single 保證線程安全

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

return single; } }

 

這種方法雖然實現了線程安全,但是由於synchronized的同步化導致其效率會降低,

 

2.通過雙重鎖定實現單列模式的線程安全

public calss Singleton4{

    //將構造函數私有化     防止外部通過new來創建對象
    private Singleton4(){
}

   //創建一個私有靜態變數  占不創建對象
   private  static volatile Singleton4 single = null;

  //提供一個public方法 並加上synchronized關鍵字 同步化來讓外部調用 返回已構建的私有single 保證線程安全

  public static  Singleton4 getInstance(){
     if(single==null){
     // 這裡面的Singleton4.class可以為任何一個不變的值,它只是一個標識,用來給線程看的 
     synchronized(Singleton4.class){
      if(single==null){
        single=new Singleton4();
      }   
}
}
  return single;
}
}

這種方法實現單列模式 保證了線程的安全性同時提高了效率,而且節約記憶體空間,只有在第一次調用的時候才會創建對象。

在創建靜態變數single時 所加的關鍵字volatile, 因為構造函數大致可被分為兩部分 一是先分配記憶體並複製 二然後再初始化 所以不加volatile可能導致雖然修改了single的值但是並沒有對其初始化 當線程2進入的時候雖然判定條件single==null 為false 而直接返回single,而此時的single 只是開闢了記憶體空間和賦值而並未被初始化 導致程式運行崩潰; 所以需要加上volatile。

3.通過構造一個靜態內部類實現單列模式的線程安全

public class Singleton5{

  //私有化構造函數
  private Singleton5(){
}

  //創建一個私有靜態內部類 並提供一個靜態方法 來創建單一實列對象
  
  private static class Instance{
    private static returnInstance(){
    // 使用final關鍵字 讓single不可被修改
      private static final Singleton5  single =new Singleton5();

} }
//提供一個公共方法給外部來獲取唯一的對象 public static Singleton5(){ retrun Instance.returnInstance(); } }

這種方法通過靜態內部類來實現,由於在類載入的時候 內部類如果沒有被使用 其中的single仍然是不會被創建的,只有當外部調用getInstance方法時,它才會被載入從而創建single對象,所以這種方法來實現單列模式的線程安全即保證了在創建該類的實列時只能創建一個,又保證了線程的安全性,而且不會造成資源浪費。

 

總結

 懶漢式和餓漢式的區別

從名字上來看,餓漢式急於創建類的唯一實列,即無論類是否調用,它都會創建好唯一的實列在那,雖然消耗一定的記憶體空間,但是其調用速度較快,並且實現代碼簡單。

相對於懶漢式 ,它是先不創建唯一實列,只有在調用getInstance方法時才會創建,所以叫懶漢式。 它基礎的實現方式只能適合單一線程使用,其餘的三種方式可以保證多線程的使用安全,而這三個方法又各有所長。

對於懶漢式的方法1來說,使用synchronized加鎖過大,導致其效率降低影響性能。對於方法2來說使用了雙層鎖定來實現,比方1的效率高性能要更好,但是其需要加上volatile關鍵字保證最初進入的兩個線程返回的結果一致,而對於volatile關鍵字涉及到了jvm的底層實現,我本身並不熟悉,所以有待以後加深瞭解,而且在其他單列模式實現的文章中看到過使用雙層鎖定的時候通過定義一個臨時變數來 替換第二層鎖,可以提高25%的效率,其具體的實現和原理也不太瞭解,有待以後學習。

從以上方法可看到,實現單列模式有以下要素

1.必須將構造方法私有化,防止外部創建對象

2.唯一的實列對象只能通過內部來創建。

3.必須要提供一個public方法讓外部能夠獲得這個唯一的實列對象。


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

-Advertisement-
Play Games
更多相關文章
  • yaml文件處理(http://pyyaml.org/wiki/PyYAMLDocumentation) 摘要: 本文講的是yaml在python上的使用教程詳解, YAML是一種容易人類閱讀、適合表示程式語言的數據結構、可用於不同程式間交換數據、支持泛型工具、支持串列處理、豐富的表達能力和可擴展性 ...
  • Numpy指南筆記 第2章:Numpy基礎 創建多維數組# coding:utf-8import numpy as npm=np.array([np.arange(2),np.arange(2)])print mprint m.shape 一維數組切片和索引# coding:utf-8import ...
  • 流 數據流 用於傳輸數據。IO流 Input/Output流。數據從外部流向程式 輸入流;數據從程式流向外部的時候--輸出流。讀取一個文件 數據從文件流向程式 輸入流;向一個文件中寫入數據 數據從程式流向文件 輸出流 根據數據流動的方向:輸入流/輸出流 根據數據傳輸的形式:位元組流/字元流 輸入流 輸 ...
  • 要求: Readme: 運行程式,輸入薪水,根據商品列表的序號選擇購買的商品,可以選擇多次購買,或者不購買 流程圖: 代碼: ...
  • #列印實心菱形,思路:分上下,i控制行,j控制列印的空格數,k控制列印的*數量row = int(input("please input a raw number: "))for i in range(row): #i控制行數 for j in range(row-1-i):#空格數和行數的關係 p ...
  • XML文件處理 XML文件處理,有好幾種方式,這裡介紹一下xml.etree.ElementTree as ET。 註意:xml.etree.ElementTree模塊在應對惡意結構數據時顯得並不安全。 每個element對象都具有以下屬性: 1. tag:string對象,表示數據代表的種類; 2 ...
  • 一.ServletContext 介面(javax.servlet)定義:public interface ServletContext原理: Tomcat啟動的時候,需要識別webapps下的各個WEB應用,識別各個WEB應用的同時為每個WEB應用創建對應的對象ServletContext,一個W... ...
  • 最近在做ProtoBuf相關的項目,其中用到了動態解析,網上看了下相關資料和博文都比較少,自己來寫一個記錄一下學習過程。 Protocol Buffers是結構化數據格式標準,提供序列化和反序列方法,用於存儲和交換。語言中立,平臺無關、可擴展。目前官方提供了C++、Java、Python API,也 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...