【Spring篇01】:Bean的線程安全問題總結

文章目錄

  • 1. 核心問題:Spring 框架中的 Bean 是線程安全的嗎?
  • 2. 最佳實踐與解決方案
    • 禁止方案:濫用`prototype`作用域
    • 推薦方案(按優先級排序)
  • 3. 生產環境中的典型案例
    • Case 1:訂單服務統計
    • Case 2:用戶會話存儲
  • 4. 關鍵總結

1. 核心問題:Spring 框架中的 Bean 是線程安全的嗎?

核心點:

  • Spring 中的 Bean 默認是單例singleton)的。
  • 默認不線程安全: Spring 框架本身不對單例 Bean 進行線程安全封裝。
  • 線程安全取決于使用方式: 如果 Bean 的狀態是不可變的,或者不包含可變狀態,則在某種程度上是線程安全的。如果 Bean 包含可變狀態且多線程同時訪問,就需要考慮線程安全問題。
  • 解決方案: 改變作用域(prototype,可多例)或自行處理線程同步。

讓我們用一個通俗的類比來理解:

類比:一個公共圖書館的書籍

  • Spring 容器: 想象一下 Spring 容器是一個大型的公共圖書館。
  • Bean: 圖書館里的每一本書都是一個 Bean。
  • 單例 Bean: 想象一下圖書館里只有 一本 特別重要的參考書(比如《Spring 官方文檔》),所有想查閱這本書的人(線程)都必須共用這一本。這就是單例 Bean。
  • 多例 Bean (Prototype): 想象一下圖書館里有很多本同一本書(比如《Java 編程入門》),每個人都可以拿一本自己的去讀。這就是多例 Bean。
  • Bean 的狀態: 書籍的內容就是 Bean 的狀態。
  • 可變狀態: 如果這本書允許你在上面做筆記、劃線、修改內容,那么這本書就是具有可變狀態的。
  • 不可變狀態: 如果這本書不允許任何修改,只能閱讀,那么這本書就是具有不可變狀態的。
  • 線程: 來圖書館查閱書籍的每個人就是一個線程。

現在,我們來套用類比來理解線程安全問題:

  • 單例 Bean (只有一本參考書): 如果多個讀者(線程)同時想要在同一本參考書(單例 Bean)上做筆記(修改狀態),就會產生沖突。第一個讀者寫了一半,第二個讀者也開始寫,內容就會混亂。這就是 線程不安全
  • 多例 Bean (很多本入門書): 如果每個讀者(線程)都拿一本自己的入門書(多例 Bean),他們可以在自己的書上隨意做筆記(修改狀態),互不影響。這就是 線程安全
  • 不可變狀態的單例 Bean (只能閱讀的參考書): 如果這本參考書不允許做任何修改,多個讀者(線程)同時閱讀(訪問不可變狀態),他們不會互相干擾。盡管是同一本書,但因為內容不可修改,所以是 線程安全 的。
  • 可變狀態的單例 Bean (允許做筆記的參考書): 如果這本參考書允許做筆記,多個讀者(線程)同時做筆記,就會產生線程不安全問題。

2. 最佳實踐與解決方案

禁止方案:濫用prototype作用域

  • 問題:每次請求創建新Bean實例,導致內存飆升、GC壓力增大,違背單例設計初衷。
  • 適用場景:僅當Bean需要持有請求級狀態(如用戶會話數據)時使用。

推薦方案(按優先級排序)

方案適用場景實現方式案例
無狀態設計絕大多數業務邏輯移除成員變量,用局部變量/參數傳遞數據Service層業務方法
ThreadLocal線程綁定的數據(如用戶身份)ThreadLocal<UserContext>權限校驗、數據庫路由
同步鎖(synchronized)低并發場景的簡單狀態synchronized方法/代碼塊本地計數器
并發工具類復雜狀態管理AtomicInteger, ConcurrentHashMap分布式ID生成、緩存
不可變對象配置類等只需初始化的數據final修飾字段,無setter方法系統參數配置Bean

3. 生產環境中的典型案例

Case 1:訂單服務統計

@Service
public class OrderService {// 錯誤!多線程下totalOrders可能少加private long totalOrders = 0; // 正確方案:使用AtomicLongprivate final AtomicLong totalOrders = new AtomicLong(0);public void placeOrder() {// 業務邏輯...totalOrders.incrementAndGet();}
}

Case 2:用戶會話存儲

@Service
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {  // 使用request作用域替代單例private String userId;// getter/setter...
}// 更優方案:ThreadLocal(避免創建過多對象)
public class UserContext {private static final ThreadLocal<String> USER_HOLDER = new ThreadLocal<>();public static void setUserId(String id) { USER_HOLDER.set(id); }public static String getUserId() { return USER_HOLDER.get(); }
}

4. 關鍵總結

  1. 默認規則:Spring單例Bean非線程安全,安全與否取決于開發者的設計
  2. 黃金準則:優先設計無狀態Bean,必須維護狀態時用并發工具ThreadLocal
  3. 避坑指南
    • 避免在單例Bean中定義非final成員變量
    • 慎用prototype作用域
    • 同步鎖范圍要最小化(鎖方法不如鎖代碼塊)

延伸思考:為什么Spring MVC的Controller默認單例卻安全?
:Controller中處理的HttpServletRequest和響應對象本質是每個請求獨享(由Tomcat線程池分配),與單例Controller實例無關。

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

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

相關文章

本地項目上傳git

將您本地的項目代碼上傳到一個私有的、別人看不見的 GitHub 倉庫&#xff0c;是進行云端協作&#xff08;如使用 Google Colab&#xff09;、版本控制和代碼備份的最佳實踐。這是一個非常重要的技能。 整個過程可以分為三個部分&#xff1a; 準備工作&#xff1a;在您的電腦上…

【.NET Framework 窗體應用程序項目結構介紹】

在使用 Visual Studio (VS) 開發 .NET Framework 窗體應用程序&#xff08;Windows Forms App&#xff09; 時&#xff0c;項目結構通常包含以下核心文件夾和文件。以下是詳細介紹&#xff1a; 1. 項目根目錄下的主要文件 (1) .csproj 文件 作用&#xff1a;C# 項目文件&…

【SpringAI】4.多模態提問

SpringAI多模態提問 概述 SpringAI支持多模態輸入&#xff0c;允許AI模型同時處理文本和圖像內容。這對于需要視覺理解的AI應用場景非常有用&#xff0c;如圖像描述、視覺問答、圖像分析等。 核心概念 1. Media類 SpringAI使用Media類來表示多模態內容&#xff0c;支持圖…

自動化提示工程:未來AI優化的關鍵突破

自動化提示工程:未來AI優化的關鍵突破 自動化提示工程能夠自動化或半自動化地生成或優化提示詞,以探索大規模的提示詞組合,并通過 自動優化技術提升提示詞生成的穩定性? 依據自動化提示工程實現形式在邏輯推理和效能導向 兩個維度的取舍上,將其分為基于思維鏈的自動化提示工…

多模態大語言模型arxiv論文略讀(148)

A Comprehensive Survey and Guide to Multimodal Large Language Models in Vision-Language Tasks ?? 論文標題&#xff1a;A Comprehensive Survey and Guide to Multimodal Large Language Models in Vision-Language Tasks ?? 論文作者&#xff1a;Chia Xin Liang, P…

關于.net core開發的實體所有注解詳解

以下是對 .NET Core 開發中實體類&#xff08;用于數據模型&#xff09;和 Web API 控制器/方法&#xff08;用于定義接口&#xff09;常用注解屬性&#xff08;Attributes&#xff09;的詳細說明與示例&#xff0c;涵蓋數據驗證、API 行為控制、序列化、Swagger/OpenAPI 文檔生…

【安全工具】SQLMap 使用詳解:從基礎到高級技巧

目錄 簡介 一、安裝與基礎配置 1. 安裝方法 2. 基本語法 二、基礎掃描技術 1. 簡單檢測 2. 指定參數掃描 3. 批量掃描 三、信息收集 1. 獲取數據庫信息 2. 獲取當前數據庫 3. 獲取數據庫用戶 4. 獲取數據庫版本 四、數據提取技術 1. 列出所有表 2. 提取表數據 …

Redis大Key拆分實戰指南:從問題定位到落地優化

引言 最近在項目里遇到一個棘手問題&#xff1a;生產環境的Redis突然變“卡”了&#xff01;查詢延遲從幾毫秒飆升到幾百毫秒&#xff0c;監控面板顯示某個節點CPU使用率飆到90%。排查半天才發現&#xff0c;原來是某個用戶訂單的Hash Key太大了——單Key存了100多萬個訂單字段…

RabbitMQ簡單消息發送

RabbitMQ簡單消息發送 簡單代碼實現RabbitMQ消息發送 需要的依賴 <!--rabbitmq--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId><version>x.x.x</version>&l…

【閱讀筆記】基于雙邊濾波改進的空域濾波算法

一、雙邊濾波空域濾波算法 雙邊濾波是一種典型的非線性濾波算法。基于高斯濾波&#xff0c;雙邊濾波利用強度的變化來保存邊緣信息&#xff0c;解決了邊緣模糊在視覺觀感上認為重要信息丟失的問題。雙邊濾波的濾波效果主要取決于兩個參數&#xff1a;兩個像素的空間鄰近性和灰…

華為交換機堆疊與集群技術深度解析附帶腳本

一、引言 在企業園區網、數據中心等網絡場景中&#xff0c;為了提升網絡的可靠性、擴展性和管理效率&#xff0c;華為交換機提供了堆疊&#xff08;Stack&#xff09;和集群&#xff08;CSS&#xff0c;Cluster Switch System &#xff09;技術。這兩種技術能夠將多臺物理交換…

Python網絡爬蟲(十三)- 數據解析模塊 BeautifulSoup

1、BS4簡介 BeautifulSoup(簡稱 BS4) 是一個用于解析 HTML 和 XML 文檔的 Python 第三方庫。它能夠從網頁或其他 HTML/XML 格式的文本中提取數據,并將其轉換為結構化的對象,方便開發者快速定位、提取和操作所需信息。它的核心功能是通過解析器將無序的標記語言轉換為樹形結…

如何使用 Pytorch Lightning 啟用早停機制

【PL 基礎】如何啟用早停機制 摘要1. on_train_batch_start()2. EarlyStopping Callback 摘要 本文介紹了兩種在 PyTorch Lightning 中實現早停機制的方法。第一種是通過重寫on_train_batch_start()方法手動控制訓練流程&#xff1b;第二種是使用內置的EarlyStopping回調&#…

深入理解前綴和與差分算法及其C++實現

前綴和與差分是算法競賽和編程中非常重要的兩種技巧&#xff0c;它們能夠高效地處理區間查詢和區間更新問題。本文將詳細介紹這兩種算法的原理、應用場景以及C實現。 一、前綴和算法 1.1 前綴和的基本概念 前綴和&#xff08;Prefix Sum&#xff09;是一種預處理技術&#x…

HugeGraph【部署】Linux單機部署

注: hugegraph從版本 1.5.0 開始&#xff0c;需要 Java11 運行時環境 一、安裝JDK11 1.下載JDK11 https://www.oracle.com/java/technologies/downloads/#java11 2.解壓縮包 tar -zxvf jdk-11.0.27_linux-x64_bin.tar.gz 3.修改/etc/profile環境變量 export JAVA_HOME/usr…

C++異步編程里避免超時機制

C標準庫中時鐘&#xff08;Clock&#xff09; 這段內容主要介紹了C標準庫中**時鐘&#xff08;Clock&#xff09;**的概念和分類&#xff0c;以及它們在時間測量中的作用。以下是關鍵信息的解讀&#xff1a; 一、時鐘的核心特性 C中的時鐘是一個類&#xff0c;提供以下四個基…

npm install安裝不成功(node:32388)怎么解決?

如果在執行 npm install 時出現問題&#xff0c;尤其是 node:32388 相關的錯誤&#xff0c;這通常意味著某些依賴或配置出了問題。這里有一些常見的解決方法&#xff0c;你可以嘗試&#xff1a; 1. 清除 npm 緩存 有時候&#xff0c;npm 緩存問題會導致安裝失敗。你可以清除 …

Ubuntu-18.04-bionic 的apt的/etc/apt/sources.list 更換國內鏡像軟件源 筆記250702

Ubuntu-18.04-bionic 的apt的/etc/apt/sources.list更換國內鏡像軟件源 筆記250702 為 Ubuntu 18.04 LTS&#xff08;代號 Bionic Beaver&#xff09;更換 /etc/apt/sources.list 為國內鏡像源 備份/etc/apt/sources.list文件 sudo cp -a /etc/apt/sources.list /etc/apt/sou…

【運維系列】【ubuntu22.04】安裝GitLab

一.下載安裝文件 rootgitlab:~# wget https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/9/gitlab-ce-17.4.0-ce.0.el9.x86_64.rpm二.執行安裝腳本 2.1 先執行安裝前的命令 rootgitlab:~# apt install -y perl-interpreter rootgitlab:~# apt install -y openssh-s…

Cisco ASA防火墻查看ACL的條目數量

這里顯示的條目數量為ACE, ACE是啥&#xff1f; ACE全稱&#xff1a; access-list entry ACE指的是ACL條目展開后的數量&#xff0c; 啥叫展開&#xff1f; 示例&#xff1a; access-list out-in extend permit tcp80&443 host 1.1.1.1 host 2.2.2.2這種配置是占1條&#…