【JAVA多線程】線程池概論

目錄

1.概述

2.ThreadPoolExector

2.1.參數

2.2.新任務提交流程

2.3.拒絕策略

2.4.代碼示例


1.概述

線程池的核心:

線程池的實現原理是個標準的生產消費者模型,調用方不停向線程池中寫數據,線程池中的線程組不停從隊列中取任務。

實現線程池需要考慮的幾個核心因素:

  • 隊列的長度

  • 隊列滿后,后面來的線程如何處理

隊列的長度:

用來存線程這個隊列的長度太小了可能會不夠用,要是沒有限制又可能導致機器的物理內存耗盡,所以最好的方式就是給這個隊列一個初始化的長度,然后允許這個隊列動態擴容。

隊列滿后,后面來的任務如何處理:

隊列滿了之后新來的任務如何處理?也就是拒絕策略,關于這個拒絕策略,是直接拒絕丟棄掉?還是把隊列中的老任務丟棄掉給它讓位置?還是說不走線程池,直接新開一條線程來執行?

繼承體系:

可以看到頂級父接口提供了規范標準,真正干活兒的實現類只有ThreadPoolExcutor和ScheduleThreadPoolExecutor。

本文主要以ThreadPoolExcutor為切入聊一下線程池的核心概念,由于ScheduleThreadPoolExecutor主要是用來做延遲任務和周期任務的,以它為切入來聊線程池的核心概念并不是那么合適,后面會有文章專門聊一聊JDK基于線程池打造的一整套延遲任務、周期任務、異步任務等,這些任務調度體系。

2.ThreadPoolExector

2.1.參數

public class ThreadPoolExecutor extends AbstractExecutorService{private final AtomicInteger ctl;//狀態變量private final BlockingQueue<Runnable> workQueue;//任務隊列private final ReentrantLock mainLock;//用于保證線程池中各變量之間的互斥private final HashSet<ThreadPoolExecutor.Worker> workers;//線程組
}
private final class Worker extends AbstractQueuedSynchronizer implements Runnable{final Thread thread;//被封裝的線程Runnable firstTask;//worker收到的第一個任務volatile long completedTasks;//worker執行完畢的任務數
}

線程池的核心參數為

  • corePoolSize:在線程池中始終維護的線程個數.

  • maxPoolSize:在corePooSize已滿、隊列也滿的情況下,擴 充線程至此值。

  • keepAliveTime/TimeUnit:maxPoolSize 中的空閑線程,銷 毀所需要的時間,總線程數收縮回corePoolSize。

  • blockingQueue:線程池所用的隊列類型。

  • threadFactory:線程創建工廠,可以自定義,也有一個默 認的。

  • RejectedExecutionHandler:corePoolSize 已滿,隊列已 滿,maxPoolSize 已滿,最后的拒絕策略。

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.acc = System.getSecurityManager() == null ?null :AccessController.getContext();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

2.2.新任務提交流程

入口在ThreadPoolExector.execute(Runnable command)

public void execute(Runnable command) {if (command == null)throw new NullPointerException();
?int c = ctl.get();//如果當前線程組中的線程數量小于核心線程數,直接開一個新線程來執行該任務if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}//如果當前線程組中的線程數量大于等于核心線程數,將該任務放入隊列中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))//這時候再失敗意味著線程組數量已經大于maxPoolSize且任務隊列已滿,直接執行拒絕策略reject(command);}

2.3.拒絕策略

ThreadPoolExector一共提供了四種拒絕策略:

  • AbortPolicy,默認拒絕策略,直接拋出異常。

  • CallerRunsPolicy,讓任務在調用者的線程中執行,線程池不對任務做處理。

  • DiscardPolicy,線程池直接把任務丟棄掉,就當什么都沒有發生。

  • DiscardOldestPolicy,把隊列中最老的任務刪掉,將新任務放入隊列。

2.4.代碼示例

在使用線程池的時候并不需要我們手動去創建,JDK中有工具類來幫我們創建各種線程池,這個工具類只是包了一層,其底層還是創建的我們上面聊的這些線程池的實現類,以下是代碼示例:

import java.util.concurrent.*;public class ThreadPoolExamples {public static void main(String[] args) throws InterruptedException {// 固定大小的線程池示例fixedThreadPoolExample();// 單線程線程池示例singleThreadExecutorExample();// 緩存線程池示例cachedThreadPoolExample();// 定時線程池示例scheduledThreadPoolExample();}/*** 創建一個固定大小的線程池,該線程池中的線程數量固定,不會因為任務的增加而增加新的線程。*/private static void fixedThreadPoolExample() {ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); // 創建一個包含5個線程的線程池for (int i = 0; i < 10; i++) {final int taskId = i;fixedThreadPool.execute(() -> {System.out.println("FixedThreadPool: Task ID " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("FixedThreadPool: Task ID " + taskId + " finished by " + Thread.currentThread().getName());});}fixedThreadPool.shutdown(); // 關閉線程池try {fixedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}}/*** 創建一個單線程線程池,所有的任務都將在同一個線程中依次執行。*/private static void singleThreadExecutorExample() {ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); // 創建一個單線程的線程池for (int i = 0; i < 10; i++) {final int taskId = i;singleThreadExecutor.execute(() -> {System.out.println("SingleThreadExecutor: Task ID " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("SingleThreadExecutor: Task ID " + taskId + " finished by " + Thread.currentThread().getName());});}singleThreadExecutor.shutdown(); // 關閉線程池try {singleThreadExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}}/*** 創建一個緩存線程池,該線程池會根據需要創建新線程,但會在線程閑置后回收線程。*/private static void cachedThreadPoolExample() {ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); // 創建一個緩存線程池for (int i = 0; i < 10; i++) {final int taskId = i;cachedThreadPool.execute(() -> {System.out.println("CachedThreadPool: Task ID " + taskId + " is running by " + Thread.currentThread().getName());try {Thread.sleep(1000); // 模擬耗時操作} catch (InterruptedException e) {e.printStackTrace();}System.out.println("CachedThreadPool: Task ID " + taskId + " finished by " + Thread.currentThread().getName());});}cachedThreadPool.shutdown(); // 關閉線程池try {cachedThreadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);} catch (InterruptedException e) {e.printStackTrace();}}/*** 創建一個定時線程池,可以安排任務在指定時間執行,或定期執行任務。*/private static void scheduledThreadPoolExample() {ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); // 創建一個包含5個線程的定時線程池Runnable task = () -> System.out.println("ScheduledThreadPool: Task executed at: " + System.currentTimeMillis());// 安排在1秒后執行一次,然后每隔2秒重復執行scheduledThreadPool.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS);try {Thread.sleep(10000); // 主線程休眠10秒,以便觀察任務執行情況} catch (InterruptedException e) {e.printStackTrace();}scheduledThreadPool.shutdown(); // 關閉線程池}
}

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

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

相關文章

最新版Python安裝教程

一、安裝Python 1.下載Python 訪問Python官網&#xff1a; https:/www.oython.orgl 點擊downloads按鈕&#xff0c;在下拉框中選擇系統類型(windows/Mac OS./Linux等) 選擇下載最新穩定版本的Python 以下內容以演示安裝Windows操作系統64位的python 左邊是穩定發布版本Stabl…

python網絡編程-TCP/IP

鏈路層 幀組成&#xff08;按順序&#xff09;&#xff1a; 目標MAC&#xff1a;6B 源MAC&#xff1a;6B 類型&#xff1a;2B 數據&#xff1a;46B-1500B CRC&#xff1a;4B 其中&#xff0c;源MAC為主機網卡地址&#xff0c;類型為來源網絡層的數據類型&#xff0c;ipv…

Self-Instruct構造Prompt的例子

人工構造一批Prompt做種子。&#xff08;Starting with a small seed set of human-written tasks&#xff09;每次把一些種子后來生成的Prompt&#xff0c;放到Input里做few-shot examples&#xff0c;用LLM生成更多的Prompt&#xff1b;&#xff08;Using the LLM to generat…

PyTorch學習之torch.transpose函數

PyTorch學習之torch.transpose函數 一、簡介 torch.transpose 函數我們用于交換張量的維度。 二、語法 torch.transpose 函數用于交換給定張量的兩個維度&#xff0c;其語法如下&#xff1a; torch.transpose(input, dim0, dim1)三、參數 input&#xff1a;待交換維度的張…

kotlin 基礎

文章目錄 1、安裝 Java 和 Kotlin 環境2、程序代碼基本結構3、變量的聲明與使用4、數據類型5、數字類型的運算1&#xff09;布爾類型2&#xff09;字符類型3&#xff09;字符串類型 6、 選擇結構1)&#xff08;if - else&#xff09;2&#xff09; 選擇結構&#xff08;when&am…

useImperativeHandle淺談

useImperativeHandle 是 React Hooks 提供的一個高級功能&#xff0c;它允許你在函數式組件中自定義并暴露特定的實例值或方法給父組件。主要的作用是&#xff1a; 自定義對外暴露的實例值或方法: 通常情況下&#xff0c;函數式組件內部的實例值或方法對外是不可見的&#xff0…

如何有效管理你的Facebook時間線?

Facebook作為全球最大的社交平臺之一&#xff0c;每天都有大量的信息和內容在用戶的時間線上展示。有效管理你的Facebook時間線&#xff0c;不僅可以提升用戶體驗&#xff0c;還能夠幫助你更好地控制信息流和社交互動。本文將探討多種方法和技巧&#xff0c;幫助你有效管理個人…

分班結果老師怎么發給家長?

分班結果老師怎么發給家長&#xff1f; 隨著新學期的腳步漸近&#xff0c;老師們的工作也變得愈發繁忙。從準備教學計劃到整理課程材料&#xff0c;每一項任務都不容小覷。而其中&#xff0c;分班結果的告知工作&#xff0c;更是讓不少老師頭疼不已。傳統的分班通知方式&#…

7、Redis主從復制過程

Redis主從復制過程 ? 當一個Redis節點&#xff08;Slave節點&#xff09;接受到類似slaveof 127.0.0.1 6380的指令直到其可以從master持續復制數據&#xff0c;大致經歷如下過程&#xff1a; 1、保存master地址 ? 當slave接收到slaveof命令后&#xff0c;slave會立即將新的…

Python爬蟲與數據可視化:構建完整的數據采集與分析流程

Python爬蟲技術概述 Python爬蟲是一種自動化的數據采集工具&#xff0c;它可以模擬瀏覽器行為&#xff0c;訪問網頁并提取所需信息。Python爬蟲的實現通常涉及以下幾個步驟&#xff1a; 發送網頁請求&#xff1a;使用requests庫向目標網站發送HTTP請求。獲取網頁內容&#xf…

.gitignore 的奧秘:前端開發者必須了解的文件忽略規則(二).gitignore 匹配規則

.gitignore 匹配規則 Git 版本管理在開發中場景&#xff0c;其中.gitignore也是Git中必不可少的配置文件&#xff0c;.gitignore 文件用于告訴 Git 哪些文件或目錄應該被忽略&#xff0c;即不被版本控制系統跟蹤和提交。 系列文章&#xff0c;上一篇介紹了&#xff1a;.gitigno…

Python 如何批量壓縮PDF文件或減小PDF文件大小

目錄 安裝Python PDF庫 Python通過壓縮圖片來減小PDF文件大小 Python通過壓縮字體或取消嵌入字體來減小PDF文件大小 Python通過刪除不必要的內容如附件、注釋或表單來減小PDF文件大小 總結 PDF文件憑借其平臺無關性和便攜性&#xff0c;已經成為日常辦公和信息共享的首選格…

15集終于編譯成功了-了個球!編譯TFLite Micro語音識別工程-《MCU嵌入式AI開發筆記》

15集終于編譯成功了-個球&#xff01;編譯TFLite Micro語音識別工程-《MCU嵌入式AI開發筆記》 還是參考這個官方文檔&#xff1a; https://codelabs.developers.google.cn/codelabs/sparkfun-tensorflow#2 全是干貨&#xff01; 這里面提到的這個Micro工程已經移開了&#xff1…

【微服務】springboot對接Prometheus指標監控使用詳解

目錄 一、前言 二、微服務監控概述 2.1 微服務常用監控指標 2.2 微服務常用指標監控工具 2.3 微服務使用Prometheus監控優勢 三、環境準備 3.1 部署Prometheus服務 3.2 部署Grafana 服務 3.3 提前搭建springboot工程 3.3.1 引入基礎依賴 3.3.2 配置Actuator 端點 3.…

【Linux】信號的處理

你很自由 充滿了無限可能 這是很棒的事 我衷心祈禱你可以相信自己 無悔地燃燒自己的人生 -- 東野圭吾 《解憂雜貨店》 信號的處理 1 信號的處理2 內核態 VS 用戶態3 鍵盤輸入數據的過程4 如何理解OS如何正常的運行5 如何進行信號捕捉信號處理的總結6 可重入函數volatile關…

C# 如何獲取屬性的displayName的3種方式

文章目錄 1. 使用特性直接訪問2. 使用GetCustomAttribute()方法通過反射獲取3. 使用LINQ查詢總結和比較 在C#中&#xff0c;獲取屬性的displayName可以通過多種方式實現&#xff0c;包括使用特性、反射和LINQ。下面我將分別展示每種方法&#xff0c;并提供具體的示例代碼。 1.…

數據庫逆向工程工具reverse_sql

reverse_sql 是一個用于解析和轉換 MySQL 二進制日志&#xff08;binlog&#xff09;的工具。它可以將二進制日志文件中記錄的數據庫更改操作&#xff08;如插入、更新、刪除&#xff09;轉換為反向的 SQL 語句&#xff0c;以便對系統或人為產生的誤操作進行數據回滾和恢復。 *…

JVM專題之垃圾收集器

JVM參數 3.1.1 標準參數 -version -help -server -cp 3.1.2 -X參數 非標準參數,也就是在JDK各個版本中可能會變動 ``` -Xint 解釋執行 -Xcomp 第一次使用就編譯成本地代碼 -Xmixed 混合模式,JVM自己來決定 3.1.3 -XX參數 > 使用得最多的參數類型 > > 非…

RedHat運維-Linux文本操作基礎-牛客AWK

1. 查看static這個連接文件是否自動連接的命令是____________________________________&#xff1b; 2. 查看default這個連接文件是否自動連接的命令是_____________________________________&#xff1b; 3. 查看con0這個連接文件是否自動連接的命令是_______________________…

【Python】已解決:(paddleocr導包報錯)ModuleNotFoundError: No module named ‘paddle’

文章目錄 一、分析問題背景二、可能出錯的原因三、錯誤代碼示例四、正確代碼示例五、注意事項 已解決&#xff1a;&#xff08;paddleocr導包報錯&#xff09;ModuleNotFoundError: No module named ‘paddle’ 一、分析問題背景 近日&#xff0c;一些使用PaddleOCR庫進行文字…