Java并發編程-線程池(二)

文章目錄

  • 線程池的實現原理
    • execute(Runnable command)
      • **1. 階段一:嘗試創建核心線程**
      • **2. 階段二:嘗試將任務加入隊列**
      • **3. 階段三:嘗試創建非核心線程或拒絕任務**
      • **關鍵機制與設計思想**

線程池的實現原理

當向線程池提交一個任務之后,線程池是如何處理這個任務的呢?根據剛剛講的線程池參數的含義,我們來看一下線程池 的主要處理流程。

從圖中可以看出,當提交一個新任務到線程池時,線程池的處理流程是這樣的, 這個很關鍵,面試必問。

在這里插入圖片描述

  1. 判斷核心線程池是否已滿,即線程數是否達到corePoolSize

如果不是,則創建一個新的工作線程來執行任務。如果核心線程池里的線程已經滿了,則進入下個流程。

  • 判斷工作隊列是否已經滿。 BlockingQueue

如果工作隊列沒有滿,則將新提交的任務存儲在這 個工作隊列里。如果工作隊列滿了,則進入下個流程。

  • 判斷線程池是否已滿,即線程數是否達到maxPoolSize

如果沒有,則創建一個新的工作線程 來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。

再來看看 ThreadPoolExecutor執行execute()方法的圖:

在這里插入圖片描述

按照我們上面說的, ThreadPoolExecutor執行execute方法也會分為這幾種情況。

  1. 如果當前運行的線程少于corePoolSize,則創建新線程來執行任務(注意,執行這一步驟需要獲取全局鎖)。

  2. 如果運行的線程等于或多于corePoolSize,則將任務加入BlockingQueue。

  3. 如果無法將任務加入BlockingQueue(隊列已滿),則創建新的線程來處理任務(注意,執行這一步驟需要獲取全局鎖)。

  4. 如果創建新線程將使當前運行的線程超出maximumPoolSize,任務將被拒絕,并調用 RejectedExecutionHandler.rejectedExecution()方法。

ThreadPoolExecutor采取上述步驟的總體設計思路,是為了在執行execute()方法時,盡可能地避免獲取全局鎖, 因為很明顯這是一個嚴重的瓶頸。

在ThreadPoolExecutor完成預熱之后 , 也就是當前運行的線程數大于等于corePoolSize,幾乎所有的execute()方法調用都是執行步驟2,而步驟2不需要獲取全局鎖。

通過流程分析,我們很直觀地了解了線程池的工作原理,接下來, 我們再通過源代碼來看看具體是如何實現的

execute(Runnable command)

//高3位表示狀態,低29位表示線程數
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {//如果當前工作線程數小于核心線程數(corePoolSize),//則嘗試創建新線程作為核心線程并立即執行任務if (addWorker(command, true)) // 以核心模式創建Workerreturn;c = ctl.get(); // 若創建失敗(如線程池已關閉),重新獲取ctl值}if (isRunning(c) && workQueue.offer(command)) { // 檢查狀態并嘗試入隊int recheck = ctl.get();if (! isRunning(recheck) && remove(command))// 線程池已關閉且任務成功移除reject(command); // 拒絕任務else if (workerCountOf(recheck) == 0) //無存活線程addWorker(null, false); //創建非核心線程防止隊列任務積壓}else if (!addWorker(command, false))// 以非核心模式創建Workerreject(command); // 拋出RejectedExecutionException異常
}

1. 階段一:嘗試創建核心線程

int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true)) // 以核心模式創建Workerreturn;c = ctl.get(); // 若創建失敗(如線程池已關閉),重新獲取ctl值
}
  • 目標:如果當前工作線程數小于核心線程數(corePoolSize),則嘗試創建新線程作為核心線程并立即執行任務。

  • 關鍵操作

    • workerCountOf(c):解析 ctl 變量(高3位表示狀態,低29位表示線程數)獲取當前工作線程數。

    • addWorker(command, true):嘗試以核心線程限制(corePoolSize)創建工作者(Worker),command 作為首任務。

    • 失敗處理:若線程池已關閉(狀態非 RUNNING)或并發沖突導致創建失敗,則進入階段二。

2. 階段二:嘗試將任務加入隊列

if (isRunning(c) && workQueue.offer(command)) { // 檢查狀態并嘗試入隊int recheck = ctl.get(); // 重新獲取狀態以應對并發變化if (!isRunning(recheck) && remove(command)) // 線程池已關閉且任務成功移除reject(command); // 拒絕任務else if (workerCountOf(recheck) == 0) // 無存活線程(例如核心線程超時被回收)addWorker(null, false); // 創建非核心線程(后續從隊列取任務)
}
  • 目標:當核心線程已滿,嘗試將任務加入阻塞隊列(如 LinkedBlockingQueue)。

  • 關鍵操作

    • 雙重狀態檢查

      1. 初始入隊前校驗線程池是否處于運行狀態(isRunning(c))。

      2. 入隊后再次校驗(recheck),避免在入隊期間線程池被關閉。

    • 處理極端情況

      • 若線程池已關閉且成功從隊列移除任務,則觸發拒絕策略。

      • 若所有工作線程意外終止(例如異常退出),則新建非核心線程(參數 firstTask = null),強制處理隊列中的積壓任務。此處的 null 表示新線程不立即執行提交的command,而是直接從隊列中獲取任務(通過 Worker.run() 中的循環邏輯)。此時創建的非核心線程雖然無初始任務,但會主動消費隊列中積累的任務,確保隊列不積壓。

      while (running) {Job job = null;synchronized (jobs) {if (jobs.isEmpty()) jobs.wait(); // 從隊列取任務job = jobs.removeFirst();}if (job != null) job.run();
      }
      

3. 階段三:嘗試創建非核心線程或拒絕任務

else if (!addWorker(command, false)) // 以非核心模式創建Workerreject(command); // 隊列已滿且線程數達到maximumPoolSize,拒絕任務
  • 目標:當隊列已滿時,嘗試創建非核心線程(線程數上限為 maximumPoolSize)。

  • 關鍵操作

    • addWorker(command, false):以非核心模式創建工作者,直接執行當前任務。

    • 失敗條件

      • 線程數已達 maximumPoolSize

      • 線程池已關閉(非 RUNNING 狀態)。

    • 拒絕策略:調用 RejectedExecutionHandler.rejectedExecution(),默認拋出 RejectedExecutionException

關鍵機制與設計思想

  1. 全局鎖(Global Lock)的應用

    • addWorker() 方法內部通過鎖(如 ReentrantLock)同步線程池狀態修改操作(例如增減線程、更新 ctl),確保原子性。
  2. 減少鎖競爭優化

    • 在核心線程已預熱的情況下,多數任務直接通過隊列處理(階段二),避免了頻繁獲取鎖的性能損耗。
  1. Worker執行邏輯(補充)

    • 每個 Worker 啟動后執行 runWorker() 方法,循環從隊列中獲取任務。

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

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

相關文章

清華大學開源軟件鏡像站地址

清華大學開源軟件鏡像站&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/

腦機接口技術:開啟人類與機器融合的新時代

摘要 腦機接口&#xff08;BCI&#xff09;技術作為一項前沿科技&#xff0c;正在逐步打破人類與機器之間的溝通障礙&#xff0c;為醫療、娛樂、教育等多個領域帶來前所未有的變革。本文將詳細介紹腦機接口技術的基本原理、發展現狀、應用場景以及面臨的挑戰和未來發展趨勢&…

2025前端面試遇到的問題(vue+uniapp+js+css)

Vue相關面試題 vue2和vue3的區別 一、核心架構差異 特性Vue2Vue3響應式系統基于Object.defineProperty基于Proxy&#xff08;支持動態新增/刪除屬性&#xff09;代碼組織方式Options API&#xff08;data/methods分塊&#xff09;Composition API&#xff08;邏輯按功能聚合&am…

Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解

Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解 目錄 Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解效果一覽基本介紹程序設計參考資料效果一覽 基本介紹 Matlab基于SSA-MVMD麻雀算法優化多元變分模態分解 可直接運行 分解效果好 適合作為創新點(Matlab完整源碼和數據),…

Gatsby知識框架

一、Gatsby 基礎概念 1. 核心特性 基于React的靜態站點生成器&#xff1a;使用React構建&#xff0c;輸出靜態HTML/CSS/JS GraphQL數據層&#xff1a;統一的數據查詢接口 豐富的插件系統&#xff1a;超過2000個官方和社區插件 高性能優化&#xff1a;自動代碼分割、預加載、…

【論信息系統項目的資源管理】

論信息系統項目的資源管理 前言一、規劃好資源管理&#xff0c;為保證項目完成做好人員規劃二、估算活動資源&#xff0c;為制訂項目進度計劃提供資源需求三、獲取項目資源&#xff0c;組建一個完備的項目團隊四、建設項目團隊&#xff0c;提高工作能力&#xff0c;促進團隊成員…

idea Maven 打包SpringBoot可執行的jar包

背景&#xff1a;當我們需要坐聯調測試的時候&#xff0c;需要對接前端同事&#xff0c;則需要打包成jar包直接運行啟動服務 需要將項目中的pom文件增加如下代碼配置&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</gr…

VScode 的插件本地更改后怎么生效

首先 vscode 的插件安裝地址為 C:\Users\%USERNAME%\.vscode\extensions 找到你的插件包進行更改 想要打印日志&#xff0c;用下面方法 vscode.window.showErrorMessage(console.log "${name}" exists.); 打印結果 找到插件&#xff0c;點擊卸載 然后點擊重新啟動 …

Python訓練營打卡——DAY24(2025.5.13)

目錄 一、元組 1. 通俗解釋 2. 元組的特點 3. 元組的創建 4. 元組的常見用法 二、可迭代對象 1. 定義 2. 示例 3. 通俗解釋 三、OS 模塊 1. 通俗解釋 2. 目錄樹 四、作業 1. 準備工作 2. 實戰代碼示例? 3. 重要概念解析 一、元組 是什么??&#xff1a;一種…

初入OpenCV

OpenCV簡介 OpenCV是一個開源的跨平臺計算機視覺庫&#xff0c;它實現了圖像處理和計算機視覺方面的很多通用算法。 應用場景&#xff1a; 目標識別&#xff1a;人臉、車輛、車牌、動物&#xff1b; 自動駕駛&#xff1b;醫學影像分析&#xff1b; 視頻內容理解分析&#xff…

訊聯云庫項目開發日志(一)

1、設計數據庫 2、寫基本框架 entity、controller、service、exception、utils、mapper mapper層&#xff1a; 生成了一系列的CRUD方法 工具類&#xff1a;線程安全的日期工具類、 ??參數校驗工具類? 線程安全的日期工具類??&#xff1a;主要用于 ??日期格式化&…

langchain學習

無門檻免費申請OpenAI ChatGPT API搭建自己的ChatGPT聊天工具 https://nuowa.net/872 基本概念 LangChain 能解決大模型的兩個痛點&#xff0c;包括模型接口復雜、輸入長度受限離不開自己精心設計的模塊。根據LangChain 的最新文檔&#xff0c;目前在 LangChain 中一共有六大…

Protobuf工具

#region 知識點一 什么是 Protobuf //Protobuf 全稱是 protocol - buffers&#xff08;協議緩沖區&#xff09; // 是谷歌提供給開發者的一個開源的協議生成工具 // 它的主要工作原理和我們之前做的自定義協議工具類似 // 只不過它更加的完善&…

zst-2001 上午題-歷年真題 軟件工程(38個內容)

CMM 軟件工程 - 第1題 b 軟件工程 - 第2題 c 軟件工程 - 第3題 c 軟件工程 - 第4題 b 軟件工程 - 第5題 b CMMI 軟件工程 - 第6題 0.未完成&#xff1a;未執行未得到目標。1.已執行&#xff1a;輸入-輸出實現支持2.已管理&#xff1a;過程制度化&#x…

軟考架構師考試-UML圖總結

考點 選擇題 2-4分 案例分析0~1題和面向對象結合考察&#xff0c;前幾年固定一題。近3次考試沒有出現。但還是有可能考。 UML圖概述 1.用例圖&#xff1a;描述系統功能需求和用戶&#xff08;參與者&#xff09;與系統之間的交互關系&#xff0c;聚焦于“做什么”。 2.類圖&…

數據結構(七)——圖

一、圖的定義與基本術語 1.圖的定義 圖G由頂點集V和邊集E組成&#xff0c;記為G(V,E)&#xff0c;其中V(G)表示圖G中頂點的有限非空集&#xff1b;E(G)表示圖G中頂點之間的關系&#xff08;邊&#xff09;的集合 注意&#xff1a;線性表可以是空表&#xff0c;樹可以是空樹&…

Android7 Input(六)InputChannel

概述: 本文講述Android Input輸入框架中 InputChannel的功能。從前面的講述&#xff0c;我們知道input系統服務最終將輸入事件寫入了InputChannel&#xff0c;而input屬于system_server進程&#xff0c;App屬于另外一個進程&#xff0c;當Input系統服務想要把事件傳遞給App進行…

【 Redis | 實戰篇 秒殺實現 】

目錄 前言&#xff1a; 1.全局ID生成器 2.秒殺優惠券 2.1.秒殺優惠券的基本實現 2.2.超賣問題 2.3.解決超賣問題的方案 2.4.基于樂觀鎖來解決超賣問題 3.秒殺一人一單 3.1.秒殺一人一單的基本實現 3.2.單機模式下的線程安全問題 3.3.集群模式下的線程安全問題 前言&…

如何用URDF文件構建機械手模型并與MoveIt集成

機械手URDF文件的編寫 我們用urdf文件來描述我們的機械手的外觀以及物理性能。這里為了簡便&#xff0c;就只用了基本的圓柱、立方體了。追求美觀的朋友&#xff0c;還可以用dae文件來描述機械手的外形。 import re def remove_comments(text):pattern r<!--(.*?)-->…

《構建社交應用的安全結界:雙框架對接審核API的底層邏輯與實踐》

用戶生成內容如潮水般涌來。從日常的生活分享&#xff0c;到激烈的觀點碰撞&#xff0c;這些內容賦予社交應用活力&#xff0c;也帶來管理難題。虛假信息、暴力言論、侵權內容等不良信息&#xff0c;如同潛藏的暗礁&#xff0c;威脅著社交平臺的健康生態。內容審核機制&#xf…