分布式微服務系統架構第156集:JavaPlus技術文檔平臺日更-Java線程池使用指南


title: java線程池使用 author: 哪吒 date: '2023-06-15'

點擊勘誤issues,哪吒感謝大家的閱讀

Java線程池使用指南

1. 線程池基礎使用

1.1 創建線程池的方式

方式一:使用Executors工具類(不推薦)
// 1. 固定大小線程池
ExecutorService fixedPool = Executors.newFixedThreadPool(5);// 2. 緩存線程池
ExecutorService cachedPool = Executors.newCachedThreadPool();// 3. 單線程池
ExecutorService singlePool = Executors.newSingleThreadExecutor();// 4. 定時任務線程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(3);

為什么不推薦使用Executors?

問題分析:
┌─────────────────────────────────────────────────────────┐
│ ?newFixedThreadPool & newSingleThreadExecutor ? ? ? ? ?│
│ ?↓ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │
│ ?使用LinkedBlockingQueue(無界隊列) ? ? ? ? ? ? ? ? ? ?│
│ ?↓ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │
│ ?可能導致內存溢出(OOM) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?│
│ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │
│ ?newCachedThreadPool ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?│
│ ?↓ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │
│ ?最大線程數為Integer.MAX_VALUE ? ? ? ? ? ? ? ? ? ? ? ? ?│
│ ?↓ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │
│ ?可能創建大量線程導致系統崩潰 ? ? ? ? ? ? ? ? ? ? ? ? ? ?│
└─────────────────────────────────────────────────────────┘
方式二:手動創建ThreadPoolExecutor(推薦)
public?class?ThreadPoolFactory?{/*** 創建標準線程池*/public?static?ThreadPoolExecutor?createStandardPool()?{returnnew?ThreadPoolExecutor(5, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 核心線程數10, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??// 最大線程數60L, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 空閑時間TimeUnit.SECONDS, ? ? ? ? ? ? ? ? ? ? ??// 時間單位new?ArrayBlockingQueue<>(100), ? ? ? ? ?// 工作隊列new?ThreadFactory() { ? ? ? ? ? ? ? ? ??// 線程工廠privatefinal?AtomicInteger threadNumber =?new?AtomicInteger(1);@Overridepublic?Thread?newThread(Runnable r)?{Thread t =?new?Thread(r,?"CustomPool-"?+ threadNumber.getAndIncrement());t.setDaemon(false); ?// 設置為用戶線程t.setPriority(Thread.NORM_PRIORITY);return?t;}},new?ThreadPoolExecutor.CallerRunsPolicy()?// 拒絕策略);}
}

2. 常用線程池類型及應用場景

2.1 CPU密集型任務線程池

public?class?CPUIntensiveThreadPool?{/*** CPU密集型任務線程池配置* 核心線程數 = CPU核心數 + 1*/public?static?ThreadPoolExecutor?createCPUIntensivePool()?{int?corePoolSize = Runtime.getRuntime().availableProcessors() +?1;returnnew?ThreadPoolExecutor(corePoolSize,corePoolSize,0L,TimeUnit.MILLISECONDS,new?LinkedBlockingQueue<>(50),new?ThreadFactory() {privatefinal?AtomicInteger threadNumber =?new?AtomicInteger(1);@Overridepublic?Thread?newThread(Runnable r)?{Thread t =?new?Thread(r,?"CPU-Pool-"?+ threadNumber.getAndIncrement());t.setDaemon(false);return?t;}},new?ThreadPoolExecutor.AbortPolicy());}// 使用示例:計算密集型任務public?static?void?main(String[] args)?{ThreadPoolExecutor executor = createCPUIntensivePool();// 提交計算任務for?(int?i =?0; i <?10; i++) {finalint?taskId = i;executor.submit(() -> {long?result = fibonacci(35);?// 計算斐波那契數列System.out.println("任務"?+ taskId +?"計算結果:"?+ result +?" - 線程:"?+ Thread.currentThread().getName());});}shutdownGracefully(executor);}private?static?long?fibonacci(int?n)?{if?(n <=?1)?return?n;return?fibonacci(n -?1) + fibonacci(n -?2);}private?static?void?shutdownGracefully(ExecutorService executor)?{executor.shutdown();try?{if?(!executor.awaitTermination(60, TimeUnit.SECONDS)) {executor.shutdownNow();}}?catch?(InterruptedException e) {executor.shutdownNow();Thread.currentThread().interrupt();}}
}

2.2 IO密集型任務線程池

public?class?IOIntensiveThreadPool?{/*** IO密集型任務線程池配置* 核心線程數 = CPU核心數 * 2*/public?static?ThreadPoolExecutor?createIOIntensivePool()?{int?corePoolSize = Runtime.getRuntime().availableProcessors() *?2;returnnew?ThreadPoolExecutor(corePoolSize,corePoolSize *?2,60L,TimeUnit.SECONDS,new?LinkedBlockingQueue<>(200),new?ThreadFactory() {privatefinal?AtomicInteger threadNumber =?new?AtomicInteger(1);@Overridepublic?Thread?newThread(Runnable r)?{Thread t =?new?Thread(r,?"IO-Pool-"?+ threadNumber.getAndIncrement());t.setDaemon(false);return?t;}},new?ThreadPoolExecutor.CallerRunsPolicy());}// 使用示例:文件讀寫任務public?static?void?main(String[] args)?{ThreadPoolExecutor executor = createIOIntensivePool();// 提交IO任務for?(int?i =?0; i <?20; i++) {finalint?taskId = i;executor.submit(() -> {try?{// 模擬文件讀寫操作Thread.sleep(1000);?// 模擬IO等待System.out.println("任務"?+ taskId +?"完成文件操作 - 線程:"?+?Thread.currentThread().getName());}?catch?(InterruptedException e) {Thread.currentThread().interrupt();}});}shutdownGracefully(executor);}private?static?void?shutdownGracefully(ExecutorService executor)?{executor.shutdown();try?{if?(!executor.awaitTermination(60, TimeUnit.SECONDS)) {executor.shutdownNow();}}?catch?(InterruptedException e) {executor.shutdownNow();Thread.currentThread().interrupt();}}
}

2.3 定時任務線程池

public?class?ScheduledThreadPoolExample?{public?static?void?main(String[] args)?throws?InterruptedException?{ScheduledThreadPoolExecutor scheduler =?new?ScheduledThreadPoolExecutor(3,new?ThreadFactory() {privatefinal?AtomicInteger threadNumber =?new?AtomicInteger(1);@Overridepublic?Thread?newThread(Runnable r)?{Thread t =?new?Thread(r,?"Scheduler-"?+ threadNumber.getAndIncrement());t.setDaemon(false);return?t;}});// 1. 延遲執行任務scheduler.schedule(() -> {System.out.println("延遲3秒執行的任務 - "?+?new?Date());},?3, TimeUnit.SECONDS);// 2. 固定頻率執行任務ScheduledFuture<?> fixedRateTask = scheduler.scheduleAtFixedRate(() -> {System.out.println("每2秒執行一次的任務 - "?+?new?Date());},?1,?2, TimeUnit.SECONDS);// 3. 固定延遲執行任務ScheduledFuture<?> fixedDelayTask = scheduler.scheduleWithFixedDelay(() -> {System.out.println("上次執行完成后延遲1秒再執行 - "?+?new?Date());try?{Thread.sleep(500);?// 模擬任務執行時間}?catch?(InterruptedException e) {Thread.currentThread().interrupt();}},?1,?1, TimeUnit.SECONDS);// 運行10秒后停止Thread.sleep(10000);fixedRateTask.cancel(false);fixedDelayTask.cancel(false);scheduler.shutdown();}
}

3. 線程池監控與管理

3.1 線程池狀態監控

public?class?ThreadPoolMonitor?{/*** 創建可監控的線程池*/public?static?ThreadPoolExecutor?createMonitorablePool()?{returnnew?ThreadPoolExecutor(5,?10,?60L, TimeUnit.SECONDS,new?ArrayBlockingQueue<>(100),new?ThreadFactory() {privatefinal?AtomicInteger threadNumber =?new?AtomicInteger(1);@Overridepublic?Thread?newThread(Runnable r)?{Thread t =?new?Thread(r,?"Monitor-Pool-"?+ threadNumber.getAndIncrement());t.setDaemon(false);return?t;}},new?ThreadPoolExecutor.CallerRunsPolicy()) {@Overrideprotected?void?beforeExecute(Thread t, Runnable r)?{super.beforeExecute(t, r);System.out.println("任務開始執行 - 線程:"?+ t.getName());}@Overrideprotected?void?afterExecute(Runnable r, Throwable t)?{super.afterExecute(r, t);if?(t !=?null) {System.err.println("任務執行異常:"?+ t.getMessage());}?else?{System.out.println("任務執行完成");}}@Overrideprotected?void?terminated()?{super.terminated();System.out.println("線程池已終止");}};}/*** 打印線程池狀態信息*/public?static?void?printPoolStatus(ThreadPoolExecutor executor)?{System.out.println("\n=== 線程池狀態信息 ===");System.out.println("核心線程數:"?+ executor.getCorePoolSize());System.out.println("最大線程數:"?+ executor.getMaximumPoolSize());System.out.println("當前線程數:"?+ executor.getPoolSize());System.out.println("活躍線程數:"?+ executor.getActiveCount());System.out.println("隊列中任務數:"?+ executor.getQueue().size());System.out.println("已完成任務數:"?+ executor.getCompletedTaskCount());System.out.println("總任務數:"?+ executor.getTaskCount());System.out.println("是否關閉:"?+ executor.isShutdown());System.out.println("是否終止:"?+ executor.isTerminated());System.out.println("========================\n");}
}

3.2 線程池異常處理

public?class?ThreadPoolExceptionHandling?{/*** 創建帶異常處理的線程池*/public?static?ThreadPoolExecutor?createSafeThreadPool()?{returnnew?ThreadPoolExecutor(5,?10,?60L, TimeUnit.SECONDS,new?ArrayBlockingQueue<>(50),new?ThreadFactory() {privatefinal?AtomicInteger threadNumber =?new?AtomicInteger(1);@Overridepublic?Thread?newThread(Runnable r)?{Thread t =?new?Thread(r,?"Safe-Pool-"?+ threadNumber.getAndIncrement());t.setDaemon(false);// 設置未捕獲異常處理器t.setUncaughtExceptionHandler((thread, ex) -> {System.err.println("線程 "?+ thread.getName() +?" 發生未捕獲異常:"?+ ex.getMessage());ex.printStackTrace();});return?t;}},new?ThreadPoolExecutor.CallerRunsPolicy());}/*** 安全任務包裝器*/public?static?Runnable?wrapTask(Runnable task)?{return?() -> {try?{task.run();}?catch?(Exception e) {System.err.println("任務執行異常:"?+ e.getMessage());e.printStackTrace();// 可以在這里添加異常上報邏輯}};}public?static?void?main(String[] args)?{ThreadPoolExecutor executor = createSafeThreadPool();// 提交可能拋異常的任務executor.submit(wrapTask(() -> {System.out.println("正常任務執行");}));executor.submit(wrapTask(() -> {thrownew?RuntimeException("模擬任務異常");}));// 使用Future處理異常Future<?> future = executor.submit(() -> {thrownew?RuntimeException("Future異常");});try?{future.get();}?catch?(ExecutionException e) {System.err.println("通過Future捕獲異常:"?+ e.getCause().getMessage());}?catch?(InterruptedException e) {Thread.currentThread().interrupt();}executor.shutdown();}
}

4. 最佳實踐與注意事項

4.1 線程池參數配置指南

public?class?ThreadPoolConfigGuide?{/*** 根據任務類型配置線程池*/publicstaticclass?ThreadPoolConfigurator?{// CPU密集型任務配置public?static?ThreadPoolExecutor?forCPUIntensive()?{int?processors = Runtime.getRuntime().availableProcessors();returnnew?ThreadPoolExecutor(processors, ? ? ? ? ? ? ? ? ? ?// 核心線程數 = CPU核心數processors, ? ? ? ? ? ? ? ? ? ?// 最大線程數 = CPU核心數0L, TimeUnit.MILLISECONDS, ? ??// 無空閑時間new?ArrayBlockingQueue<>(processors *?2),?// 隊列大小適中new?ThreadPoolExecutor.AbortPolicy());}// IO密集型任務配置public?static?ThreadPoolExecutor?forIOIntensive()?{int?processors = Runtime.getRuntime().availableProcessors();returnnew?ThreadPoolExecutor(processors *?2, ? ? ? ? ? ? ? ?// 核心線程數 = CPU核心數 * 2processors *?4, ? ? ? ? ? ? ? ?// 最大線程數 = CPU核心數 * 460L, TimeUnit.SECONDS, ? ? ? ??// 空閑60秒回收new?LinkedBlockingQueue<>(1000),?// 較大的隊列new?ThreadPoolExecutor.CallerRunsPolicy());}// 混合型任務配置public?static?ThreadPoolExecutor?forMixed()?{int?processors = Runtime.getRuntime().availableProcessors();returnnew?ThreadPoolExecutor(processors +?1, ? ? ? ? ? ? ? ?// 核心線程數 = CPU核心數 + 1processors *?2, ? ? ? ? ? ? ? ?// 最大線程數 = CPU核心數 * 260L, TimeUnit.SECONDS,new?ArrayBlockingQueue<>(200),new?ThreadPoolExecutor.CallerRunsPolicy());}}
}

4.2 常見問題與解決方案

public?class?ThreadPoolTroubleshooting?{/*** 問題1:線程池任務積壓* 解決方案:動態調整線程池大小*/publicstaticclass?DynamicThreadPool?{privatefinal?ThreadPoolExecutor executor;privatefinal?ScheduledExecutorService monitor;public?DynamicThreadPool(ThreadPoolExecutor executor)?{this.executor = executor;this.monitor = Executors.newSingleThreadScheduledExecutor();startMonitoring();}private?void?startMonitoring()?{monitor.scheduleAtFixedRate(() -> {int?queueSize = executor.getQueue().size();int?activeCount = executor.getActiveCount();int?corePoolSize = executor.getCorePoolSize();int?maxPoolSize = executor.getMaximumPoolSize();// 隊列積壓嚴重,增加線程if?(queueSize >?100?&& activeCount >= corePoolSize *?0.8) {int?newCoreSize = Math.min(corePoolSize +?1, maxPoolSize);if?(newCoreSize > corePoolSize) {executor.setCorePoolSize(newCoreSize);System.out.println("增加核心線程數至:"?+ newCoreSize);}}// 隊列空閑,減少線程if?(queueSize <?10?&& activeCount < corePoolSize *?0.5?&& corePoolSize >?2) {executor.setCorePoolSize(corePoolSize -?1);System.out.println("減少核心線程數至:"?+ (corePoolSize -?1));}},?0,?30, TimeUnit.SECONDS);}}/*** 問題2:任務執行時間過長* 解決方案:任務超時控制*/publicstaticclass?TimeoutTaskExecutor?{privatefinal?ThreadPoolExecutor executor;public?TimeoutTaskExecutor(ThreadPoolExecutor executor)?{this.executor = executor;}public?<T>?T?executeWithTimeout(Callable<T> task,?long?timeout, TimeUnit unit)?throws?InterruptedException, ExecutionException, TimeoutException?{Future<T> future = executor.submit(task);try?{return?future.get(timeout, unit);}?catch?(TimeoutException e) {future.cancel(true);?// 取消任務throw?e;}}}
}

4.3 性能優化建議

線程池性能優化清單:1. 參數配置優化? 根據任務類型選擇合適的核心線程數? 設置合理的最大線程數和隊列大小? 選擇適當的拒絕策略2. 任務設計優化? 避免任務執行時間過長? 合理拆分大任務? 避免任務間的強依賴關系3. 監控與調優? 定期監控線程池狀態? 記錄任務執行時間? 根據監控數據調整參數4. 資源管理? 及時關閉線程池? 避免創建過多線程池? 合理設置線程優先級

5. 總結

Java線程池是并發編程的重要工具,正確使用線程池可以:

  • 提高性能:減少線程創建和銷毀的開銷

  • 控制資源:限制并發線程數量,避免系統資源耗盡

  • 提高響應性:復用線程,快速響應任務請求

  • 便于管理:統一管理線程生命周期

關鍵要點

  1. 避免使用Executors創建線程池,推薦手動創建ThreadPoolExecutor

  2. 根據任務類型(CPU密集型/IO密集型)合理配置參數

  3. 實施有效的監控和異常處理機制

  4. 注意線程池的優雅關閉

  5. 定期評估和調優線程池配置

通過遵循這些最佳實踐,可以充分發揮線程池的優勢,構建高性能、穩定的并發應用程序。

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

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

相關文章

【最新版】點大全能版v2.6.7.1 含匯付斗拱插件+uniapp前端

一.介紹V2全能版本、獨立版本全開源&#xff0c;含鏈動21&#xff0c;匯付斗拱?、排隊免單、推三返1 &#xff0c;扶持金&#xff0c;平級獎&#xff0c;團隊業績獎&#xff0c;酒店管理&#xff0c;約車&#xff0c;餐飲等眾多營銷功能&#xff0c;商城系統版本號為2.6.7.1&a…

Go語言高級面試必考:切片(slice)你真的掌握了嗎?

目錄 1. 切片是個啥?從數組到切片的靈魂進化 數組與切片的愛恨情仇 切片的內存結構:三巨頭共舞 切片的初始化方式:靈活到飛起 切片的“引用”特性:福也是禍 源碼初探:切片的誕生 2. 切片三劍客:len、cap 和底層數組的三角戀 len 和 cap 的微妙關系 切片共享的秘密…

monorepo + Turborepo --- 開發應用程序

目錄 配置開發任務 在 dev 之前運行設置任務 運行特定應用程序 使用終端 UI 與任務交互 監聽模式 watch 將 turbo watch 與持久任務一起使用 依賴感知的持久任務 沒有依賴感知的持久任務 緩存 任務輸出 局限性 在 Monorepo 中開發應用程序可以解鎖強大的工作流程&…

C#字符串相關庫函數運用梳理總結 + 正則表達式詳解

C# 字符串常用庫函數總結 &#x1f539; 1. 字符串比較 方法說明示例string.Equals()比較兩個字符串是否相等&#xff08;可忽略大小寫&#xff09;string.Equals("abc", "ABC", StringComparison.OrdinalIgnoreCase) / !判斷兩個字符串是否相等/不等&quo…

投機采樣(Speculative Decoding)

投機采樣&#xff08;Speculative Decoding&#xff09; 是一種加速大型語言模型&#xff08;LLM&#xff09;推理的技術&#xff0c;其核心思想是通過預生成候選token序列并異步校驗&#xff0c;從而減少主模型的計算量&#xff0c;同時保持生成結果的準確性。 核心思想是通過…

如何將華為手機中的照片傳輸到電腦

華為手機在眾多手機品牌中以其出色的品質脫穎而出&#xff0c;尤其是其攝像頭功能。有時&#xff0c;你可能在華為手機上積累了太多有意義的照片&#xff0c;想要將這些照片上傳到電腦以釋放手機存儲空間。然而&#xff0c;出于用戶信息安全的考慮&#xff0c;一些便捷的方法可…

whitt算法之特征向量的尺度

whitt中特征值不相等判別條件另一個條件的意思&#xff0c; 實際上這兩個條件都沒用&#xff0c;不用看&#xff0c;特征值排序&#xff0c;如果現在順序對λ1/λ1‘ w λ2/λ2 -w 此時取相位就是0&#xff0c;最小了 如果相反就是面的是0我的代碼用最優相位內積去交換位置公…

【Note】《深入理解Linux內核》 第十九章:深入理解 Linux 進程通信機制

《深入理解Linux內核》 第十九章&#xff1a;深入理解 Linux 進程通信機制&#xff08;Process Communication&#xff09;關鍵詞&#xff1a;IPC、信號、管道、FIFO、消息隊列、信號量、共享內存、套接字、內核對象、同步機制一、進程通信概述 1.1 為什么需要進程通信 在 Linu…

【Mac 從 0 到 1 保姆級配置教程 19】- 英語學習篇-我的英語工作流分享(AI 輔助學習)

文章目錄前言聽力沉浸式翻譯閱讀Easydict配置自定義字典&#xff08;重點&#xff09;歐陸詞典沙拉查詞沉浸式翻譯寫作Eearthworm英文提問口語最后學習資料系列教程前言 本文介紹一下我日常如何學習和使用英語的工作流&#xff0c;包括一些常用好用的工具&#xff0c;好的工具…

從庫函數到API接口,深挖不同語言背后的“封裝”與“調用”思想

個人主頁-愛因斯晨 優秀文章推薦 文章目錄個人主頁-愛因斯晨優秀文章推薦引言一、三種調用機制概述C語言的庫函數Python 的導包機制Java 的 API 接口調用綜上&#xff1a;二、它們的相同點&#xff1a;封裝與調用三、不同之處**對比核心維度****細節串講**1. **C 語言&#xf…

基于NCNN框架在Android平臺實現YOLOv8目標檢測模型的高效部署與實踐

隨著移動設備計算能力的提升&#xff0c;越來越多的深度學習模型被部署到移動端&#xff0c;以實現實時、低延遲的應用場景。YOLO系列的在目標檢測任務中表現出色&#xff0c;具有精度高、速度快的優勢。本文將詳細介紹如何基于NCNN框架 &#xff0c;在Android平臺 上高效部署Y…

華為動態路由配置

問題描述&#xff1a;針對四個路由器在不同的網段場景中&#xff0c;對四個路由器進行動態路由配置。下面以如下場景為例&#xff0c;介紹詳細配置過程。配置過程&#xff1a; 1、每個路由器的接口配置IP地址 路由器AR1中每個接口配置IP地址。 sys # 進入系統視圖 interface g…

分布式事務解決方案(三)

在Java分布式系統領域&#xff0c;傳統強一致性方案&#xff08;如2PC、3PC&#xff09;在高并發、復雜業務場景下暴露出性能瓶頸和阻塞問題。而Saga模式與事件溯源&#xff08;Event Sourcing&#xff09;作為更具彈性和擴展性的解決方案&#xff0c;逐漸成為分布式事務處理和…

【時時三省】(C語言基礎)通過指針引用數組

山不在高&#xff0c;有仙則名。水不在深&#xff0c;有龍則靈。 ----CSDN 時時三省數組元素的指針一個變量有地址&#xff0c;一個數組包含若干元素&#xff0c;每個數組元素都在內存中占用存儲單元&#xff0c;它們都有相應的地址。指針變量既然可以指向變量&#xff0c;當然…

【WEB】Polar靶場 21-25題 詳細筆記

二十一.php very nicephp又是你 ,但是經過這么多次折磨后我感覺我已經有一點抗性了老規矩&#xff0c;先看知識點PHP 序列化是將 PHP 變量&#xff08;如對象、數組&#xff09;轉換為字符串的過程&#xff0c;便于存儲或傳輸。反序列化則是將字符串還原為原始變量。這在緩存、…

【Guava】1.0.設計虛擬機的方向

【Guava】1.0.設計虛擬機的方向虛擬機是什么&#xff1f;棧式虛擬機棧式虛擬機的優缺點題外話虛擬機是什么&#xff1f; 虛擬機&#xff08;VirtualMachine, VM&#xff09;是一種計算機程序或系統&#xff0c;它通過軟件模擬物理計算機的硬件運行環境&#xff0c;使得多個操作…

[附源碼+數據庫+畢業論文]基于Spring+MyBatis+MySQL+Maven+jsp實現的高校實驗室資源綜合管理系統,推薦!

摘 要 現代經濟快節奏發展以及不斷完善升級的信息化技術&#xff0c;讓傳統數據信息的管理升級為軟件存儲&#xff0c;歸納&#xff0c;集中處理數據信息的管理方式。本高校實驗室資源綜合管理系統就是在這樣的大環境下誕生&#xff0c;其可以幫助管理者在短時間內處理完畢龐大…

Spring Boot:影響事務回滾的幾種情況

一、Controller 捕獲異常導致事務失效 需求 我們有一個用戶注冊服務&#xff0c;注冊時需要&#xff1a; 創建用戶賬戶分配初始積分發送注冊通知 這三個操作需要在同一個事務中執行&#xff0c;任何一步失敗都要回滾。 錯誤示例&#xff1a;Controller 捕獲異常導致事務失效 Re…

如何避免分布式爬蟲被目標網站封禁?

在分布式爬蟲的大規模數據采集場景中&#xff0c;避免被目標網站封禁的核心邏輯是&#xff1a;通過技術手段模擬真實用戶行為&#xff0c;降低爬蟲行為的可識別性&#xff0c;同時建立動態適配機制應對網站反爬策略的升級。以下從請求偽裝、行為控制、資源管理、反爬對抗四個維…

Maven 打包排除特定依賴的完整指南(詳細方法 + 示例)

前言 在使用 Maven 構建 Java 項目時&#xff0c;我們常常需要對項目的打包過程進行精細化控制&#xff0c;尤其是希望排除某些特定的依賴庫。這可能是為了減小最終構建產物的體積、避免版本沖突&#xff0c;或者僅僅是為了滿足不同環境下的部署需求。 本文將詳細介紹如何在 Ma…