在 SpringBoot+Tomcat 環境中 線程安全問題的根本原因以及哪些變量會存在線程安全的問題。

文章目錄

  • 前言
  • Tomcat + SpringBoot
    • 單例加載
    • 結果分析
    • 多例加載:
    • 結果分析:
  • 哪些變量存在線程安全的問題?
    • 線程不安全
    • 線程安全
  • 總結

前言

本文帶你去深入理解為什么在web環境中(Tomcat +SpringBoot)會存在多線程的問題以及哪些變量會存在線程安全的問題。

Tomcat + SpringBoot

首先我們來看下Tomcat的多線程處理模型:

1、Tomcat內部維護一個工作線程池
2、每個HTTP請求由Tomcat線程池中的一個工作線程處理
3、在高并發場景下,多個線程同時處理不同的HTTP請求

Spring Boot是如何去加載類的:

1、@Component 等注解修飾的類類會被 Spring 掃描到,并放入容器中成為 Bean
2、Spring容器中的Bean是單例的
3、所有請求共享同一個單例的Bean 類
4、所有線程獲得的是同一個Bean 類的引用

正是由于Bean是單例的+每個HTTP請求一個工作線程處理
所以存在多個工作線程同時操作一個Bean實例,這樣就導致了多線程競爭同一個資源,進而導致線程安全的問題。

實際例子去理解單例和多例加載:

單例加載

@Component
public class SingletonCounterService {private int count = 0;public void increase() {count++;System.out.println(Thread.currentThread().getName() + " count = " + count);}
}
@SpringBootTest
public class SingletonTest {@Autowiredprivate SingletonCounterService counter;@Testpublic void testMultiThreadSingleton() throws InterruptedException {Runnable task = () -> counter.increase();Thread t1 = new Thread(task, "T1");Thread t2 = new Thread(task, "T2");Thread t3 = new Thread(task, "T3");t1.start();t2.start();t3.start();t1.join();t2.join();t3.join();}
}
T1 count = 1
T2 count = 3
T3 count = 2

結果分析

多個線程同時操作同一個SingletonCounterService實例 內部的共享變量count 導致最后 count為3 而不是每一個都為1

多例加載:

@Component
@Scope("prototype")
public class PrototypeCounterService {private int count = 0;public void increase() {count++;System.out.println(Thread.currentThread().getName() + " count = " + count);}
}
@SpringBootTest
public class PrototypeTest {@Autowiredprivate ApplicationContext context;@Testpublic void testMultiThreadPrototype() throws InterruptedException {Runnable task = () -> {PrototypeCounterService counter = context.getBean(PrototypeCounterService.class);counter.increase(); // 每個線程是自己獨立的 bean};Thread t1 = new Thread(task, "T1");Thread t2 = new Thread(task, "T2");Thread t3 = new Thread(task, "T3");t1.start();t2.start();t3.start();t1.join();t2.join();t3.join();}
}
T1 count = 1
T2 count = 1
T3 count = 1

結果分析:

每個線程拿到的是自己獨立的 bean 實例,不共享count。

哪些變量存在線程安全的問題?

經過上面的分析,你已經知道了為什么會存在多線程的問題了吧。(多個線工作線程去操作同一個類實例)那么下一步就是去定位可能存在多線程安全的變量位置。

線程不安全

1、實例變量(成員變量):

@Service
public class UserService {private User currentUser;  // 不安全:多個線程可能同時修改currentUserprivate int counter = 0;  // 不安全:多線程遞增count不是原子操作
}

2、非線程安全的實例變量

@Service
public class ReportService {private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  // 不安全:SimpleDateFormat非線程安全private Map<String, Object> dataCache = new HashMap<>();  // 不安全:HashMap非線程安全private List<User> userCache = new ArrayList<>();  // 不安全:ArrayList是線程不安全的容器 相反vector是線程安全的
}

3、靜態變量:

@Service
public class ConfigService {private static Map<String, String> globalConfig = new HashMap<>();  // 不安全:類變量本身就是跨所有實例共享 
}

線程安全

1、方法內的局部變量:

public void process() {int localCounter = 0;  // 安全:每個方法都有獨立的方法棧 局部變量不共享List<String> localList = new ArrayList<>();  // 安全:局部變量
}

2、不可變(Immutable)實例變量

private final String apiUrl = "https://api.example.com";  // 安全:不可變
private final List<String> constants = Collections.unmodifiableList(Arrays.asList("A", "B"));  // 安全:不可變集合

3、線程安全的實例變量:

private AtomicInteger counter = new AtomicInteger(0);  // 安全:原子操作
private ConcurrentHashMap<String, User> userMap = new ConcurrentHashMap<>();  // 安全:并發集合

4、ThreadLocal變量

private ThreadLocal<User> currentUser = new ThreadLocal<>();  // 安全:線程隔離

總結

在Spring+Tomcat環境中,線程安全問題的根本原因是:

Tomcat使用線程池并發處理HTTP請求
Spring默認使用單例Bean
這導致多個線程并發訪問同一個Service實例
當Service包含可變共享狀態時,就會出現線程安全問題

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

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

相關文章

npm install 相關命令

npm install 相關命令 基本安裝命令 # 安裝 package.json 中列出的所有依賴 npm install npm i # 簡寫形式# 安裝特定包 npm install <package-name># 安裝特定版本 npm install <package-name><version>依賴類型選項 # 安裝為生產依賴&#xff08;默認&…

貪心算法應用:最小反饋頂點集問題詳解

貪心算法應用&#xff1a;最小反饋頂點集問題詳解 1. 問題定義與背景 1.1 反饋頂點集定義 反饋頂點集(Feedback Vertex Set, FVS)是指在一個有向圖中&#xff0c;刪除該集合中的所有頂點后&#xff0c;圖中將不再存在任何有向環。換句話說&#xff0c;反饋頂點集是破壞圖中所…

BiliNote部署實踐

? 開源地址&#xff1a; https://github.com/JefferyHcool/BiliNote &#x1f680; 快速開始 1. 克隆倉庫 git clone https://github.com/JefferyHcool/BiliNote.git cd BiliNote mv .env.example .env2. 啟動后端&#xff08;FastAPI&#xff09; cd backend pip insta…

用go從零構建寫一個RPC(4)--gonet網絡框架重構+聚集發包

在追求高性能的分布式系統中&#xff0c;RPC 框架的底層網絡能力和數據傳輸效率起著決定性作用。經過幾輪迭代優化&#xff0c;我完成了第四版本的 RPC 框架。相比以往版本&#xff0c;這一版本的最大亮點在于 重寫了底層網絡框架 和 實現了發送端的數據聚集機制&#xff0c;這…

MySQL 高可用基石 - 復制監控與常見 HA 方案

MySQL 高可用基石 - 復制監控與常見 HA 方案 MySQL 復制核心原理 MySQL 復制允許數據從一個 MySQL 數據庫服務器(稱為主庫 - Primary,舊稱 Master)復制到一個或多個其他的 MySQL 服務器(稱為從庫 - Replica,舊稱 Slave)。 復制的主要目的: 高可用性 (High Availability…

微信小程序(uniapp)自定義 TabBar

微信小程序&#xff08;uniapp&#xff09;自定義 TabBar 實現指南 在微信小程序開發中&#xff0c;TabBar 是底部導航欄的重要組件&#xff0c;但官方提供的 TabBar 樣式和功能較為基礎&#xff0c;無法滿足所有項目的需求。本文將詳細介紹如何在 uniapp 中實現自定義 TabBar…

MLP實戰二:MLP 實現圖像數字多分類

任務 實戰&#xff08;二&#xff09;&#xff1a;MLP 實現圖像多分類 基于 mnist 數據集&#xff0c;建立 mlp 模型&#xff0c;實現 0-9 數字的十分類 task: 1、實現 mnist 數據載入&#xff0c;可視化圖形數字&#xff1b; 2、完成數據預處理&#xff1a;圖像數據維度轉換與…

BUUCTF[HCTF 2018]WarmUp 1題解

BUUCTF[HCTF 2018]WarmUp 1題解 分析解題過程代碼審計主體函數CHECK函數&#xff1a; 構造payload 總結 分析 啟動靶機&#xff0c;進入網址&#xff0c;是一張滑稽的表情包&#xff1a; 程序化F12查看源碼&#xff1a; 發現注釋內容&#xff0c;訪問 url:/source.php得到…

大陸4D毫米波雷達ARS548調試

本文介紹了大陸ARS548毫米波雷達的調試與測試流程&#xff0c;主要包括以下內容&#xff1a; 設備參數&#xff1a;最大檢測距離301m&#xff08;可調93-1514m&#xff09;&#xff0c;支持gPTP時間同步。 接線調試&#xff1a; Windows需使用USB-RJ45轉換器 Linux可直接連接網…

TDengine 的 AI 應用實戰——運維異常檢測

作者&#xff1a; derekchen Demo數據集準備 我們使用公開的 NAB數據集 里亞馬遜 AWS 東海岸數據中心一次 API 網關故障中&#xff0c;某個服務器上的 CPU 使用率數據。數據的頻率為 5min&#xff0c;單位為占用率。由于 API 網關的故障&#xff0c;會導致服務器上的相關應用…

并發編程 - go版

1.并發編程基礎概念 進程和線程 A. 進程是程序在操作系統中的一次執行過程&#xff0c;系統進行資源分配和調度的一個獨立單位。B. 線程是進程的一個執行實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。C.一個進程可以創建和撤銷多個線程;同一個進程中…

《一生一芯》數字實驗三:加法器與ALU

1. 實驗目標 設計一個能實現如下功能的4位帶符號位的 補碼 ALU&#xff1a; Table 4 ALU 功能列表 ? 功能選擇 功能 操作 000 加法 AB 001 減法 A-B 010 取反 Not A 011 與 A and B 100 或 A or B 101 異或 A xor B 110 比較大小 If A<B then out1…

解讀《網絡安全法》最新修訂,把握網絡安全新趨勢

《網絡安全法》自2017年施行以來&#xff0c;在維護網絡空間安全方面發揮了重要作用。但隨著網絡環境的日益復雜&#xff0c;網絡攻擊、數據泄露等事件頻發&#xff0c;現行法律已難以完全適應新的風險挑戰。 2025年3月28日&#xff0c;國家網信辦會同相關部門起草了《網絡安全…

Java并發編程實戰 Day 10:原子操作類詳解

【Java并發編程實戰 Day 10】原子操作類詳解 開篇 這是“Java并發編程實戰”系列的第10天&#xff0c;我們將深入探討原子操作類的核心技術——CAS原理、ABA問題以及原子類的實現機制。通過理論結合代碼實踐的方式&#xff0c;幫助讀者理解并掌握如何在實際工作中高效使用原子…

瀚文機械鍵盤固件開發詳解:HWKeyboard.h文件解析與應用

【手把手教程】從零開始的機械鍵盤固件開發&#xff1a;HWKeyboard.h詳解 前言 大家好&#xff0c;我是鍵盤DIY愛好者Despacito0o&#xff01;今天想和大家分享我開發的機械鍵盤固件核心頭文件HWKeyboard.h的設計思路和技術要點。這個項目是我多年來對鍵盤固件研究的心血結晶…

2048游戲的技術實現分析-完全Java和Processing版

目錄 簡介Processing庫基礎項目構建指南項目結構核心數據結構游戲核心機制圖形界面實現性能優化代碼詳解設計模式分析測試策略總結與展望簡介 2048是一款由Gabriele Cirulli開發的經典益智游戲。本文將深入分析其Java實現版本的技術細節。該實現使用了Processing庫來創建圖形界…

Spring Boot + Elasticsearch + HBase 構建海量數據搜索系統

Spring Boot Elasticsearch HBase 構建海量數據搜索系統 &#x1f4d6; 目錄 1. 系統需求分析2. 系統架構設計3. Elasticsearch 與 HBase 集成方案4. Spring Boot 項目實現5. 大規模搜索系統最佳實踐 項目概述 本文檔提供了基于 Spring Boot、Elasticsearch 和 HBase 構建…

【iOS】YYModel源碼解析

YYModel源碼解析 文章目錄 YYModel源碼解析前言YYModel性能優勢YYModel簡介YYClassInfo解析YYClassIvarInfo && objc_ivarYYClassMethodInfo && objc_methodYYClassPropertyInfo && property_tYYClassInfo && objc_class YYClassInfo的初始化細…

宇樹科技更名“股份有限公司”深度解析:機器人企業IPO前奏與資本化路徑

從技術落地到資本躍遷&#xff0c;拆解股改背后的上市邏輯與行業啟示 核心事件&#xff1a;股改釋放的上市信號 2025年5月28日&#xff0c;杭州宇樹科技有限公司正式更名“杭州宇樹科技股份有限公司”&#xff0c;市場主體類型變更為“股份有限公司”。盡管官方稱為常規運營調…

Android Native 內存泄漏檢測全解析:從原理到工具的深度實踐

引言 Android應用的內存泄漏不僅發生在Java/Kotlin層&#xff0c;Native&#xff08;C/C&#xff09;層的泄漏同樣普遍且隱蔽。由于Native內存不受Java虛擬機&#xff08;JVM&#xff09;管理&#xff0c;泄漏的內存無法通過GC自動回收&#xff0c;長期積累會導致應用內存占用…