技術成神之路:設計模式(一)單例模式

在軟件設計中,有時我們希望某個類的實例始終是唯一的,即無論在何處訪問這個類,都能夠得到同一個實例。單例模式(Singleton Pattern)就是為了解決這個問題而產生的。單例模式確保一個類只有一個實例,并提供一個全局訪問點。

1.定義


單例模式是一種創建型設計模式,確保一個類只有一個實例,并提供一個全局訪問點來訪問這個實例。其主要思想是將類的構造函數私有化,并通過一個靜態方法來控制實例的創建和訪問。

2.常見實現方式


單例模式有多種實現方式,下面介紹幾種常見的實現方式:

2.1餓漢式(Eager Initialization)

餓漢式是在類加載時就創建實例,這樣可以確保線程安全,并且在類首次使用前完成實例化。

示例代碼:

public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {// 私有構造函數,防止外部實例化}public static Singleton getInstance() {return INSTANCE;}
}

優點:簡單,易于理解,線程安全
缺點:類加載時即創建實例,可能造成資源浪費

如果你一定會使用該類,這種方式無疑是最簡單的方法

2.2 懶漢式(Lazy Initialization)

懶漢式是在第一次調用 getInstance() 方法時創建實例。這種方式避免了餓漢式的資源浪費問題。

示例代碼:

public class Singleton {private static Singleton instance;private Singleton() {// 私有構造函數,防止外部實例化}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

優點:實現簡單,延遲實例化,避免資源浪費
缺點:使用了 synchronized,在高并發情況下性能可能較差

每次調用getInstance()都會進行同步檢查,這樣會消耗不必要的資源,不推薦使用

2.3雙重檢查鎖(Double-Checked Locking)

雙重檢查鎖在懶漢式的基礎上,通過減少使用 synchronized 來提高性能。

示例代碼:

public class Singleton {// volatile關鍵字確保多線程下的可見性和有序性(禁止字節碼重排)private static volatile Singleton instance;private Singleton() {// 私有構造函數,避免外部直接實例化}public static Singleton getInstance() {if (instance == null) {  // 第一次檢查synchronized (Singleton.class) {if (instance == null) {  // 第二次檢查instance = new Singleton();  // 實例化}}}return instance;  // 返回實例}
}

優點:延遲實例化,提高了性能
缺點:實現復雜,容易出錯

同步代碼塊含義:因為可能會有多個線程同時通過了第一次檢查,在進入同步塊之后,再次檢查可以確保只有一個線程創建實例,最大限度地在提升性能的條件下保證了線程安全。

emm… 個人不喜歡這種笨重寫法

2.4 靜態內部類(Static Inner Class)

這種方式使用了類加載機制來確保線程安全,同時實現了延遲加載。

示例代碼:

public class Singleton {private Singleton() {// 私有構造函數,防止外部實例化}// 靜態內部類,利用類加載機制保證線程安全且延遲加載private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}

優點:延遲實例化,線程安全,實現簡單
缺點:無法傳遞外部參數

這時候就會有同學要問了,何為類加載機制,問的好,所謂類加載機制就算:JVM 在加載類的過程中,靜態內部類 SingletonHolder 中的靜態變量 INSTANCE 只會被實例化一次,由JVM保證其線程安全性,所以在多線程環境下可以安全地使用。

2.5 枚舉(Enum)

這種方法是Effective Java作者Joshua Bloch推薦的單例實現方式之一,它解決了傳統單例模式實現中的一些問題,比如序列化、反射攻擊等。

示例代碼:

public enum Singleton {INSTANCE;public void doSomething() {// 業務方法}
}

優點:簡潔,線程安全,防止反序列化破壞單例
缺點:無法靈活控制實例化過程

使用方法:

Singleton.INSTANCE.doSomething();

特點和優勢

  1. 線程安全性:
    枚舉類型的實例創建是線程安全的,JVM在加載枚舉類型時會通過類加載器保證只實例化一次。因此,多線程環境下也能保證單例的唯一性。

  2. 防止反射攻擊:
    枚舉類型的實例創建是由JVM控制的,因此無法通過反射來創建枚舉類的實例。這樣可以防止反射攻擊,即使是在枚舉類中添加了私有構造函數也不例外。

  3. 防止序列化問題:
    Java枚舉類型在序列化和反序列化時會自動處理,確保在序列化和反序列化過程中都是單例的。

  4. 簡潔且高效:
    枚舉實現單例模式非常簡潔,只需聲明一個枚舉類型即可,不需要額外的代碼來保證線程安全和單例特性。

3.單例模式的注意事項


  • 線程安全:確保在多線程環境下一個類只有一個實例。
  • 延遲加載:盡量避免在類加載時就實例化,除非明確知道實例一定會被使用。
  • 防止反射攻擊:通過在構造函數中添加判斷來防止反射創建多個實例。
  • 防止反序列化破壞單例:在實現 Serializable 接口時,提供 `readResolve 方法。

4.總結


五種創建單例的方式,大家按需選擇,核心思想都是確保一個類只有一個實例,并提供全局訪問點,沒有最好的,只有最適合的,理解不同實現方式的優缺點,可以幫助我們在實際開發中選擇最合適的方案。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/38541.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38541.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38541.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

整合web-socket的常見bug

整合文章連接 此文是記錄我上網查找整合方案時候踩的坑,特別是注冊失敗的問題,比如還有什么去掉Compoent就可以,但是這樣這個端點就失效了 特別是報錯: at org.springframework.web.socket.server.standard.ServerEndpointExporter.registerEndpoint(ServerEndpointExporter.…

大模型日報 2024-06-30

大模型日報 2024-06-30 大模型產品 Briefy: AI知識助手 摘要: Briefy是一款AI知識助手,為專業用戶簡化每日信息消費,將復雜信息提煉成結構化摘要,組織成知識庫,并以自然語言按需檢索。 Claude Projects:組織聊天與共享…

邀請函 | 極限科技全新搜索引擎 INFINI Pizza 亮相 2024 可信數據庫發展大會!

過去一年,在全球 AI 浪潮和國家數據局成立的推動下,數據庫產業變革不斷、熱鬧非凡。2024 年,站在中國數字經濟產業升級和數據要素市場化建設的時代交匯點上,“2024 可信數據庫發展大會” 將于 2024 年 7 月 16-17 日在北京悠唐皇冠…

肆拾玖坊的商業模式,49坊新零售獎金制度體系,眾籌眾創+會員制

肆拾玖坊之所以能夠在短時間內成為白酒行業的“現象級”企業,,不僅是依靠獨特商業模式,同時也依靠的是堅持用戶為核心,圍繞用戶需求,讓用戶與產品直接產生連接理念。 坐標:廈門,我是易創客肖琳 深耕社交新零售行業10年,主要提供新零售系統工…

前端技術(二)——javasctipt 介紹

一、javascript基礎 1. javascript簡介 ⑴ javascript的起源 ⑵ javascript 簡史 ⑶ javascript發展的時間線 ⑷ javascript的實現 ⑸ js第一個代碼 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>…

Vue中的axios深度探索:從基礎安裝到高級功能應用的全面指南

文章目錄 前言一、axios 請求1. axios的概念2. axios的安裝3. axiso請求方式介紹4. axios請求本地數據5. axios跨域6. axios全局注冊7. axios支持的請求類型1&#xff09;get請求2&#xff09;post請求3&#xff09;put請求4&#xff09;patch請求5&#xff09;delete請求 二、…

MyBatis操作數據庫(入門)

本節目標 使用MyBatis完成簡單的增刪改查操作&#xff0c;參數傳遞掌握MyBatis的兩種寫法&#xff1a;注解和XML方式掌握MyBatis相關的日志配置 前言 在應用分層學習中&#xff0c;我們了解web應用程序一般分為三層&#xff0c;即Controller、Service、Dao。在之前的案例中&a…

化學SCI期刊,中科院4區,易錄用,幾乎不退稿

一、期刊名稱 Chemical Papers 二、期刊簡介概況 期刊類型&#xff1a;SCI 學科領域&#xff1a;化學 影響因子&#xff1a;2.1 中科院分區&#xff1a;4區 三、期刊征稿范圍 該雜志致力于基礎和應用化學和化學工程研究。它的范圍很廣&#xff0c;涵蓋了所有化學科學&…

2024年江蘇智能制造工廠名單:我看出了未來擇業和跳槽方向

導語 大家好&#xff0c;我是社長&#xff0c;老K。專注分享智能制造和智能倉儲物流等內容。 新書《智能物流系統構成與技術實踐》 在當今這個飛速發展的時代&#xff0c;智能制造已成為推動工業進步的強大引擎。隨著技術革新的浪潮一波接一波地涌來&#xff0c;我們不禁要問&a…

動手學深度學習(Pytorch版)代碼實踐 -計算機視覺-49風格遷移

49風格遷移 讀入內容圖像&#xff1a; import torch import torchvision from torch import nn import matplotlib.pylab as plt import liliPytorch as lp from d2l import torch as d2l# 讀取內容圖像 content_img d2l.Image.open(../limuPytorch/images/rainier.jpg) plt.…

使用 Swift 遞歸搜索目錄中文件的內容,同時支持 Glob 模式和正則表達式

文章目錄 前言項目設置查找文件讀取CODEOWNERS文件解析規則搜索匹配的文件確定文件所有者輸出結果總結前言 如果你新加入一個團隊,想要快速的了解團隊的領域和團隊中擁有的代碼庫的詳細信息。 如果新團隊中的代碼庫在 GitHub / GitLab 中并且你不熟悉代碼所有權模型的概念或…

Unity開箱即用的UGUI面板的拖拽移動功能

文章目錄 &#x1f449;一、背景&#x1f449;二、效果圖&#x1f449;三、原理&#x1f449;四、核心代碼&#x1f449;五&#xff0c;總結 &#x1f449;一、背景 之前做PC項目時常常有面板拖拽移動的需求&#xff0c;今天總結封裝一下&#xff0c;做成一個隨時隨地可復用的…

More Effective C++ 35個改善編程與設計的有效方法筆記與心得 3

三. 異常 條款9&#xff1a; 利用destructors避免泄露資源 ????  在編程中&#xff0c;"資源"可以指任何系統級的有限資源&#xff0c;如內存、文件句柄、網絡套接字等。"泄露"則是指在應用程序中分配了資源&#xff0c;但在不再需要這些資源時沒有…

Linux 安裝 Redis 教程

優質博文&#xff1a;IT-BLOG-CN 一、準備工作 配置gcc&#xff1a;安裝Redis前需要配置gcc&#xff1a; yum install gcc如果配置gcc出現依賴包問題&#xff0c;在安裝時提示需要的依賴包版本和本地版本不一致&#xff0c;本地版本過高&#xff0c;出現如下問題&#xff1a…

Jupyter無法導入庫,但能在終端導入的問題

Jupyter無法導入庫&#xff0c;但能在終端導入 ?錯誤問題描述&#xff1a;conda activate LLMs激活某個Conda的環境后&#xff0c;盡管已經通過conda或者pip在這個環境中安裝了一些&#x1f40d;Python的庫&#xff0c;但無法在Jupyter中導入&#xff0c;卻能在終端成功導入。…

京東商品詳情數據接口(JD.item_get)丨京東API實時接口指南

京東商品詳情API接口&#xff08;JD.item_get&#xff09;是京東開放平臺提供的一個數據接口&#xff0c;用于獲取京東平臺上單個商品的詳細信息。 通過這個接口&#xff0c;開發者可以獲取到包括商品名稱、品牌、產地、規格參數、價格信息、銷量、評價、圖片、描述等在內的詳…

Node.js開發實戰 視頻教程 下載

ode.js開發實戰 視頻教程 下載 下載地址 https://download.csdn.net/download/m0_67912929/89487510 01-課程介紹.mp4 02-內容綜述.mp4 03-Node.js是什么? .mp4 04-Node.js可以用來做什么?.mp4 05-課程實戰項目介紹.mp4 06-什么是技術預研? .mp4 07-Node.js開發環境…

Windows 11 安裝 安卓子系統 (WSA)

How to Install Windows Subsystem for Android (WSA) on Windows 11 新手教程&#xff1a;如何安裝Windows 11 安卓子系統 說明 Windows Subsystem for Android 或 WSA 是由 Hyper-V 提供支持的虛擬機&#xff0c;可在 Windows 11 操作系統上運行 Android 應用程序。雖然它需…

【JS】注意考點

1.聲明變量時所遵循的規則&#xff1a; (1)可以使用一個保留關鍵字var同時聲明多個變量 (2)可以在聲明變量的同時對其賦值&#xff0c; (3)如果只是聲明了變量&#xff0c;并未對其賦值&#xff0c;其值就默認為 Undefined。 (4)保留關鍵字var可以用作for語句和for…in語句…

python基礎_類

在Python中&#xff0c;類&#xff08;Class&#xff09;是面向對象編程&#xff08;OOP&#xff09;的核心概念之一。類提供了一種創建新對象的模板&#xff0c;這些對象通常被稱為類的實例或對象。以下是關于Python類的一些關鍵點和特性&#xff1a; 定義類 類通過class關鍵…