單例模式:確保唯一實例的設計模式

單例模式:確保唯一實例的設計模式

一、模式核心:保證類僅有一個實例并提供全局訪問點

在軟件開發中,有些類需要確保只有一個實例(如系統配置類、日志管理器),避免因多個實例導致狀態混亂或資源浪費。

單例模式(Singleton Pattern) 通過私有化構造方法、持有唯一實例引用、提供靜態訪問接口,確保一個類在全局范圍內只有一個實例,并提供統一的訪問入口。核心解決:

  • 實例唯一性:避免創建多個實例消耗資源(如數據庫連接池、線程池)。
  • 全局可訪問性:為全局提供一個訪問點,簡化客戶端調用。
  • 延遲初始化:支持實例的延遲加載(按需創建),提升系統性能。

核心思想與 UML 類圖

單例模式的核心是私有化構造方法,并通過靜態方法返回唯一實例。常見實現方式包括:

  • 餓漢式(類加載時立即創建實例)
  • 懶漢式(第一次調用時創建實例,需處理線程安全)

PlantUML Diagram

二、核心實現:三種經典單例模式

1. 餓漢式單例(線程安全,類加載時創建實例)

public class EagerSingleton {  // 類加載時立即創建實例(靜態變量初始化)  private static final EagerSingleton instance = new EagerSingleton();  // 私有化構造方法,防止外部實例化  private EagerSingleton() {  System.out.println("創建餓漢式單例實例");  }  // 公共訪問方法,直接返回實例  public static EagerSingleton getInstance() {  return instance;  }  
}  

特點

  • 優點:簡單可靠,類加載時完成初始化,天然線程安全。
  • 缺點:無論是否使用都會創建實例,可能浪費內存(適用于實例創建成本低的場景)。

2. 懶漢式單例(線程不安全,延遲創建實例)

public class LazySingleton {  private static LazySingleton instance;  private LazySingleton() {  System.out.println("創建懶漢式單例實例");  }  // 未加鎖,多線程環境可能創建多個實例  public static LazySingleton getInstance() {  if (instance == null) {  instance = new LazySingleton();  }  return instance;  }  
}  

特點

  • 優點:延遲加載,節省內存。
  • 缺點:多線程環境下不安全,可能出現多個實例(需改進為線程安全版本)。

3. 線程安全的懶漢式(雙重檢查鎖定,DCL)

public class ThreadSafeSingleton {  private static volatile ThreadSafeSingleton instance; // volatile 禁止指令重排  private ThreadSafeSingleton() {  System.out.println("創建線程安全懶漢式單例實例");  }  public static ThreadSafeSingleton getInstance() {  // 第一次檢查:實例是否已創建  if (instance == null) {  synchronized (ThreadSafeSingleton.class) { // 同步塊,保證線程安全  // 第二次檢查:防止多個線程同時通過第一次檢查  if (instance == null) {  instance = new ThreadSafeSingleton();  }  }  }  return instance;  }  
}  

關鍵細節

  • volatile 關鍵字:確保 instance 的可見性和禁止指令重排,避免初始化未完成時被其他線程訪問。
  • 雙重檢查(Double-Check Locking):減少同步塊的競爭,提升性能。

三、進階:使用枚舉實現單例(推薦方式)

Java 枚舉天然支持單例模式,且簡潔可靠,自動處理序列化和反射攻擊問題。

public enum EnumSingleton {  INSTANCE; // 唯一實例  // 附加方法示例  public void doSomething() {  System.out.println("枚舉單例執行操作");  }  
}  

調用方式

EnumSingleton.INSTANCE.doSomething(); // 直接通過枚舉成員訪問  

優點

  • 簡潔高效,無需手動處理線程安全和序列化問題。
  • 防止通過反射創建新實例(Enum 類禁止反射攻擊)。

四、框架與源碼中的單例實踐

1. Spring 框架中的單例 Bean

Spring 默認創建的 Bean 是單例的,通過 BeanFactory 管理實例的唯一性。

@Service  
public class UserService {  // Spring 自動創建單例實例  
}  

2. Log4j 日志管理器

Log4j 的 Logger 類使用單例模式,確保每個類對應的日志記錄器唯一。

public class App {  private static final Logger logger = Logger.getLogger(App.class);  public static void main(String[] args) {  logger.info("單例日志記錄器");  }  
}  

五、避坑指南:正確使用單例模式的 4 個要點

1. 處理序列化與反序列化攻擊

若單例類實現了 Serializable 接口,需添加 readResolve() 方法防止反序列化創建新實例:

protected Object readResolve() {  return instance; // 返回現有實例,避免創建新對象  
}  

2. 防止反射攻擊

通過在構造方法中添加校驗,禁止通過反射創建多個實例:

private Singleton() {  if (instance != null) {  throw new IllegalStateException("單例實例已存在");  }  // 初始化邏輯  
}  

3. 避免單例持有長生命周期對象

單例若持有大對象或上下文(如 ApplicationContext),可能導致內存泄漏,需及時釋放資源。

4. 謹慎使用延遲加載

懶漢式單例需確保線程安全,否則可能引發 bug;若實例創建成本低,優先使用餓漢式或枚舉式。

六、總結:何時該用單例模式?

適用場景核心特征典型案例
全局唯一配置配置信息需要全局共享且唯一系統配置類(ConfigManager)
資源池管理控制資源(如數據庫連接)的創建數量數據庫連接池、線程池
日志記錄器全局共享日志實例Log4j、Logback
避免重復初始化初始化成本高,需保證僅執行一次重量級對象(如緩存管理器)

單例模式通過嚴格控制實例數量,實現了全局狀態的統一管理。下一篇我們將探討建造者模式,解析如何分步構建復雜對象,敬請期待!

擴展思考:單例模式的缺點

  • 測試困難:單例與測試框架(如 JUnit)的依賴注入沖突,需通過模擬或反射繞過。
  • 違背單一職責原則:單例可能承擔業務邏輯與實例管理雙重職責,建議將實例管理抽象為獨立工廠。

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

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

相關文章

UnoCSS原子CSS引擎-前端福音

UnoCSS是一款原子化的即時按需 CSS 引擎,其中沒有核心實用程序,所有功能都是通過預設提供的。默認情況下UnoCSS應用通過預設來實現相關功能。 UnoCSS中文文檔: https://www.unocss.com.cn 前有很多種原子化的框架,例如 Tailwind…

【Qwen2.5-VL 踩坑記錄】本地 + 海外賬號和國內賬號的 API 調用區別(阿里云百煉平臺)

API 調用 阿里云百煉平臺的海內外 API 的區別: 海外版:需要進行 API 基礎 URL 設置國內版:無需設置。 本人的服務器在香港,采用海外版的 API 時,需要進行如下API端點配置 / API基礎URL設置 / API客戶端配置&#xf…

C語言筆記(鵬哥)上課板書+課件匯總(結構體)-----數據結構常用

結構體 目錄: 1、結構體類型聲明 2、結構體變量的創建和初始化 3、結構體成員訪問操作符 4、結構體內存對齊*****(重要指數五顆星) 5、結構體傳參 6、結構體實現位段 一、結構體類型聲明 其實在指針中我們已經講解了一些結構體內容了&…

UV: Python包和項目管理器(從入門到不放棄教程)

目錄 UV: Python包和項目管理器(從入門到不放棄教程)1. 為什么用uv,而不是conda或者pip2. 安裝uv(Windows)2.1 powershell下載2.2 winget下載2.3 直接下載安裝包 3. uv教程3.1 創建虛擬環境 (uv venv) 4. uvx5. 此pip非…

網絡開發基礎(游戲方向)之 概念名詞

前言 1、一款網絡游戲分為客戶端和服務端兩個部分,客戶端程序運行在用戶的電腦或手機上,服務端程序運行在游戲運營商的服務器上。 2、客戶端和服務端之間,服務端和服務端之間一般都是使用TCP網絡通信。客戶端和客戶端之間通過服務端的消息轉…

java將pdf轉換成word

1、jar包準備 在項目中新增lib目錄&#xff0c;并將如下兩個文件放入lib目錄下 aspose-words-15.8.0-jdk16.jar aspose-pdf-22.9.jar 2、pom.xml配置 <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><versi…

【C/C++】插件機制:基于工廠函數的動態插件加載

本文介紹了如何通過 C 的 工廠函數、動態庫&#xff08;.so 文件&#xff09;和 dlopen / dlsym 實現插件機制。這個機制允許程序在運行時動態加載和調用插件&#xff0c;而無需在編譯時知道插件的具體類型。 一、 動態插件機制 在現代 C 中&#xff0c;插件機制廣泛應用于需要…

【音視頻】AAC-ADTS分析

AAC-ADTS 格式分析 AAC?頻格式&#xff1a;Advanced Audio Coding(?級?頻解碼)&#xff0c;是?種由MPEG-4標準定義的有損?頻壓縮格式&#xff0c;由Fraunhofer發展&#xff0c;Dolby, Sony和AT&T是主 要的貢獻者。 ADIF&#xff1a;Audio Data Interchange Format ?…

機器學習 Day12 集成學習簡單介紹

1.集成學習概述 1.1. 什么是集成學習 集成學習是一種通過組合多個模型來提高預測性能的機器學習方法。它類似于&#xff1a; 超級個體 vs 弱者聯盟 單個復雜模型(如9次多項式函數)可能能力過強但容易過擬合 組合多個簡單模型(如一堆1次函數)可以增強能力而不易過擬合 集成…

通過爬蟲方式實現頭條號發布視頻(2025年4月)

1、將真實的cookie貼到代碼目錄中toutiaohao_cookie.txt文件里,修改python代碼里的user_agent和video_path, cover_path等變量的值,最后運行python腳本即可; 2、運行之前根據import提示安裝一些常見依賴,比如requests等; 3、2025年4月份最新版; 代碼如下: import js…

Linux ssh免密登陸設置

使用 ssh-copy-id 命令來設置 SSH 免密登錄&#xff0c;并確保所有相關文件和目錄權限正確設置&#xff0c;可以按照以下步驟進行&#xff1a; 步驟 1&#xff1a;在源服務器&#xff08;198.120.1.109&#xff09;生成 SSH 密鑰對 如果還沒有生成 SSH 密鑰對&#xff0c;首先…

《讓機器人讀懂你的心:情感分析技術融合奧秘》

機器人早已不再局限于執行簡單機械的任務&#xff0c;人們期望它們能像人類伙伴一樣&#xff0c;理解我們的喜怒哀樂&#xff0c;實現更自然、溫暖的互動。情感分析技術&#xff0c;正是賦予機器人這種“理解人類情緒”能力的關鍵鑰匙&#xff0c;它的融入將徹底革新機器人與人…

Linux筆記---進程間通信:匿名管道

1. 管道通信 1.1 管道的概念與分類 管道&#xff08;Pipe&#xff09; 是進程間通信&#xff08;IPC&#xff09;的一種基礎機制&#xff0c;主要用于在具有親緣關系的進程&#xff08;如父子進程、兄弟進程&#xff09;之間傳遞數據&#xff0c;其核心特性是通過內核緩沖區實…

Ollama API 應用指南

1. 基礎信息 默認地址: http://localhost:11434/api數據格式: application/json支持方法: POST&#xff08;主要&#xff09;、GET&#xff08;部分接口&#xff09; 2. 模型管理 API (1) 列出本地模型 端點: GET /api/tags功能: 獲取已下載的模型列表。示例:curl http://lo…

【OSCP-vulnhub】Raven-2

目錄 端口掃描 本地/etc/hosts文件解析 目錄掃描&#xff1a; 第一個flag 利用msf下載exp flag2 flag3 Mysql登錄 查看mysql的運行權限 MySql提權&#xff1a;UDF 查看數據庫寫入條件 查看插件目錄 查看是否可以遠程登錄 gcc編譯.o文件 創建so文件 創建臨時監聽…

Podman Desktop:現代輕量容器管理利器(Podman與Docker)

前言 什么是 Podman Desktop&#xff1f; Podman Desktop 是基于 Podman CLI 的圖形化開源容器管理工具&#xff0c;運行在 Windows&#xff08;或 macOS&#xff09;上&#xff0c;默認集成 Fedora Linux&#xff08;WSL 2 環境&#xff09;。它提供與 Docker 類似的使用體驗…

極狐GitLab 權限和角色如何設置?

極狐GitLab 是 GitLab 在中國的發行版&#xff0c;關于中文參考文檔和資料有&#xff1a; 極狐GitLab 中文文檔極狐GitLab 中文論壇極狐GitLab 官網 權限和角色 (BASIC ALL) 將用戶添加到項目或群組時&#xff0c;您可以為他們分配角色。該角色決定他們在極狐GitLab 中可以執…

解鎖現代生活健康密碼,開啟養生新方式

在科技飛速發展的當下&#xff0c;我們享受著便捷生活&#xff0c;卻也面臨諸多健康隱患。想要維持良好狀態&#xff0c;不妨從這些細節入手&#xff0c;解鎖科學養生之道。? 腸道是人體重要的消化器官&#xff0c;也是最大的免疫器官&#xff0c;養護腸道至關重要。日常可多…

Kafka 主題設計與數據接入機制

一、前言&#xff1a;萬物皆流&#xff0c;Kafka 是入口 在構建實時數倉時&#xff0c;Kafka 既是 數據流動的起點&#xff0c;也是后續流處理系統&#xff08;如 Flink&#xff09;賴以為生的數據源。 但“消息進來了” ≠ “你就能處理好了”——不合理的 Topic 設計、接入方…

【繪制圖像輪廓|凸包特征檢測】圖像處理(OpenCV) -part7

15 繪制圖像輪廓 15.1 什么是輪廓 輪廓是一系列相連的點組成的曲線&#xff0c;代表了物體的基本外形。相對于邊緣&#xff0c;輪廓是連續的&#xff0c;邊緣不一定連續&#xff0c;如下圖所示。輪廓是一個閉合的、封閉的形狀。 輪廓的作用&#xff1a; 形狀分析 目標識別 …