【JavaEE】線程池

作者主頁:paper jie_博客

本文作者:大家好,我是paper jie,感謝你閱讀本文,歡迎一建三連哦。

本文于《JavaEE》專欄,本專欄是針對于大學生,編程小白精心打造的。筆者用重金(時間和精力)打造,將MySQL基礎知識一網打盡,希望可以幫到讀者們哦。

其他專欄:《MySQL》《C語言》《javaSE》《數據結構》等

內容分享:本期將會分享線程池知識.

目錄

引入

什么是線程池

為什么使用線程池會更高效

Java標準庫中的線程池

ThreadPoolExecutor

?Executors

創建線程池時,怎么設定線程數合適?

實現一個自定義的線程池

具體代碼


引入

在開始,為了解決并發編程的問題,我們引入了進程. 但隨著不斷發展我們發現進程的創建銷毀的開銷會比較大,因此我們就又引入了進程.但是隨著線程創建的頻率提高,這樣的開銷又逐漸大起來了.這個時候我們就有了兩種解決方法.第一種就是引入我們的纖程/攜程. 纖程的本質上就是在用戶態代碼中調度和控制,這樣就可以不讓內核態來調度.這樣就節省了調度的開銷.纖程就是基于線程封裝出來了,一般都是多個纖程對應一個線程.

第二個方法就是我們本文需要講的線程池~

什么是線程池

在我學變成代碼中,我們會經常遇到一些帶有池的名詞,比如: 常量池,數據庫連接池,線程池等. 池的作用就是提前將對象創建好,在需要使用的時候就去池子里面拿,用完了也不要立刻銷毀,而是再放回池里等待下次使用.這樣就可以很好的提高效率,因為節省了創建對象和銷毀對象的開銷.

而線程池也是這樣,它的本質也就是提前將線程在線程池中創建好,使用完后也不會立刻銷毀,會返回線程池等待下一次的使用.這樣也就是節省了創建和調度的開銷.

為什么使用線程池會更高效

因為從線程池中拿線程是在用戶態代碼中調度執行的,是可控的.而直接創建線程是需要在內核態中創建,這時不可控的.因為你也不知道什么時候CPU才會給創建線程.

舉個栗子:

這就像你去銀行辦理銀行卡,它可能需要你打印身份證復印件.這時你有兩個選擇: 1. 直接拿著身份證去大廳的自助打印機打印. 2.把身份證交給工作人員,由她幫你打印. 要是你自己打印就是直接去中途不會干其他的事情,但是交給工作人員保不準她可能沒有第一時間給你打印,而是先去干其他的事情. 這里辦公區就屬于內核態,大廳就屬于用戶態.?

?

Java標準庫中的線程池

ThreadPoolExecutor

Java標準庫中的線程池是ThreadPoolExecutor. 它有多個參數,我們需要去了解一下.我們可以去Java的官方文檔里面找?ThreadPoolExecutor (Java 平臺 SE 8) (oracle.com)?我們需要找到concurrent這個包.這個包里就有ThreadPoolExecutor這個類. 我們可以找到它的構造方法.

這里我們理解第4個即可,其他幾個的參數第4個都包含.

int?corePoolSize: 核心線程數.可以理解為公司里的正式員工.

int?maximumPoolSize: 最大線程數.可以理解為公司里的臨時工,公司不忙了就可以開除的那種.

long?keepAliveTime: 存活時間,就是除去核心線程的其他線程的存活時間. 可以理解為當零時工閑下來多久會被開除.

TimeUnit?unit: 存活時間的單位.

BlockingQueue<Runnable>?workQueue: 阻塞隊列,這個隊列里面存放的就是線程需要執行的任務,線程會到里面去取任務.

ThreadFactory?threadFactory: 線程工廠,線程池就是通過這個工廠類來創建線程. 本質上就是將創建線程對象的操作封裝起來且再設置一些線程的屬性.

RejectedExecutionHandler?handler: 拒絕策略. 當阻塞隊列滿了之后,再添加新的任務進來,這個拒絕策略就會出來處理. 它提供了4個方法:

1. 直接拋出異常,新的任務和舊的任務都不執行了.

2. 新的任務由這個添加新任務的線程來執行.

3. 丟棄最舊的任務,再將這個新的任務添加進阻塞隊列.

4. 丟棄這個需要添加進來的新任務,繼續照常執行.

?Executors

因為這個類的參數比較多,用起來比較復雜.Java就又用一個類將它封裝起來了,變成了一個比較簡單的線程類Executors.它也是一個工廠類. 也是通過這個類創建好不同的線程池對象,在它的內部就已經創建好了線程池對象且設置了一些它的參數.

它有好幾種創建線程池的方式:

newFixedThreadPool創建固定線程數的線程池
newCachedThreadPool創建線程數可以動態增長的線程池
newSingleThreadExecutor創建只含有單個線程的線程池
newScheduledThreadPool創建線程可以延時執行任務的線程池,類似于定時器

這里兩個類我們可以看情況來使用.

創建線程池時,怎么設定線程數合適?

這里用一句話來概括就是具體問題具體分析.

我們線程執行任務分為兩種: 一種為CPU密集型,一種為IO密集型.CPU密集型的線程就是使用CPU的時間比較長.而IO密集型的線程就是使用CPU時間少,大多數時間都是在IO等待中. 這里極端一點,都是CPU密集型的話線程池的線程數不能超過邏輯核心數,而都是IO密集型的話線程數就可以遠遠超過邏輯核心數了.

但是在我們實際開發中,一般都是CPU密集型一部分,IO密集型一部分.這種情況下我們就需要具體問題具體分析了.最好的辦法就是進行性能測試,給線程池的線程數進行多組不同數目的測試,觀察他們的系統資源開銷和時間開銷,取其中最好的即可.

實現一個自定義的線程池

這里我們實現一個簡單的固定線程數的線程池.

我們需要:
1. 一個存放任務的阻塞隊列

2. 一個核心方法來添加任務.

3. 用構造方法來指定線程數,創建好線程.

具體代碼

class MyThreadPoolExecutor3 {//1. 存放任務的阻塞隊列private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);//2. 構造方法public MyThreadPoolExecutor3(int capacity) {for(int i = 0; i <capacity; i++) {Thread t = new Thread(() -> {while(true) {Runnable runnable = null;try {runnable = queue.take();} catch (InterruptedException e) {throw new RuntimeException(e);}runnable.run();}});t.start();}}//核心方法 submit 添加方法public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}
}
public class ThreadDemo3 {public static void main(String[] args) throws InterruptedException {MyThreadPoolExecutor3 myThreadPoolExecutor3 = new MyThreadPoolExecutor3(4);for (int i = 0; i < 1000; i++) {int n = i;myThreadPoolExecutor3.submit(() -> {System.out.println(n + " " + Thread.currentThread().getName() + " hello");});}}}

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

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

相關文章

springcloud分布式事務

文章目錄 一.為什么引入分布式事務?二.理論基礎1.CAP定理2.BASE理論 三.Seata1.微服務集成Seata2.XA模式(掌握)3.AT模式(重點)4.TCC模式(重點)5.Saga模式(了解) 四.四種模式對比五.Seata高可用 一.為什么引入分布式事務? 事務的ACID原則 在大型的微服務項目中,每一個微服務都…

案例課4——智齒客服

1.公司介紹 智齒科技&#xff0c;一體化客戶聯絡中心解決方案提供商。提供基于「客戶聯絡中心」場景的一體化解決方案&#xff0c;包括公域私域、營銷服務、軟件BPO的三維一體化。 智齒科技不斷整合前沿的人工智能及大數據技術&#xff0c;已構建形成呼叫中心、機器人「在線語音…

Python中函數的遞歸調用

函數調用自己的編程方式被稱為函數的遞歸調用。遞歸通常能夠將一個大型的復雜問題的遞歸條件&#xff0c;一層一層的回溯到終止條件&#xff0c;然后再根據終止條件的運算結果&#xff0c;一層一層的遞進運算到滿足全部的遞歸條件。它能夠使用少量程序描述出解題過程中的重復運…

主機訪問Android模擬器網絡服務方法

0x00 背景 因為公司的一個手機app的開發需求&#xff0c;要嘗試鏈接手機開啟的web服務。于是在Android Studio的Android模擬器上嘗試連接&#xff0c;發現谷歌給模擬器做了網絡限制&#xff0c;不能直接連接。當然這個限制似乎從很久以前就存在了。一直沒有注意到。 0x01 And…

分銷電商結算設計

概述 分銷電商中涉及支付與結算&#xff1b;支付職責是收錢&#xff0c;結算則是出錢給各利益方&#xff1b; 結算核心圍繞業務模式涉及哪些費用&#xff0c;以及這些費用什么時候通過什么出資渠道&#xff0c;由誰給到收方利益方&#xff1b; 結算要素組成費用項結算周期出…

區塊鏈的可拓展性研究【03】擴容整理

為什么擴容&#xff1a;在layer1上&#xff0c;交易速度慢&#xff0c;燃料價格高 擴容的目的&#xff1a;在保證去中心化和安全性的前提下&#xff0c;提升交易速度&#xff0c;更快確定交易&#xff0c;提升交易吞吐量&#xff08;提升每秒交易量&#xff09; 目前方案有&…

詳解進程管理(銀行家算法、死鎖詳解)

處理機是計算機系統的核心資源。操作系統的功能之一就是處理機管理。隨著計算機的迅速發展&#xff0c;處理機管理顯得更為重要&#xff0c;這主要由于計算機的速度越來越快&#xff0c;處理機的充分利用有利于系統效率的大大提高&#xff1b;處理機管理是整個操作系統的重心所…

前后端聯調神器《OpenAPI-Codegen》

在后端開發完接口之后&#xff0c;前端如果再去寫一遍接口來聯調的話&#xff0c;會很浪費時間&#xff0c;這個時候使用OpenAPI接口文檔來生成Axios接口代碼的話&#xff0c;會大大提高我們的開發效率。 Axios引入 Axios是一個基于Promise的HTTP客戶端&#xff0c;用于瀏覽器…

Go壓測工具

前言 在做Go的性能分析調研的時候也使用到了一些壓測方面的工具&#xff0c;go本身也給我們提供了BenchMark性能測試用例&#xff0c;可以很好的去測試我們的單個程序性能&#xff0c;比如測試某個函數&#xff0c;另外還有第三方包go-wrk也可以幫助我們做http接口的性能壓測&…

C# 任務并行類庫Parallel調用示例

寫在前面 Task Parallel Library 是微軟.NET框架基礎類庫&#xff08;BCL&#xff09;中的一個&#xff0c;主要目的是為了簡化并行編程&#xff0c;可以實現在不同的處理器上并行處理不同任務&#xff0c;以提升運行效率。Parallel常用的方法有For/ForEach/Invoke三個靜態方法…

Element-UI定制化Tree 樹形控件

1.復制 說明&#xff1a;復制Tree樹形控件。 <script> export default {data() {return {data: [{label: 一級 1,children: [{label: 二級 1-1,children: [{label: 三級 1-1-1}]}]}, {label: 一級 2,children: [{label: 二級 2-1,children: [{label: 三級 2-1-1}]}, {l…

Linux:進程優先級與命令行參數

目錄 1.進程優先級 1.1 基本概念 1.2 查看系統進程 1.3 修改進程優先級的命令 2.進程間切換 2.1 相關概念 2.2 Linux2.6內核進程調度隊列&#xff08;了解即可&#xff09; 3.命令行參數 1.進程優先級 1.1 基本概念 cpu資源分配的先后順序&#xff0c;就是指進程的優…

【C++】在類外部定義成員函數時,不應該再次指定默認參數值

2023年12月10日&#xff0c;周日下午 錯誤的代碼 #include<iostream>class A { public:void fun(int a10); };void A::fun(int a10) //<----在這里報錯 {}int main() {} 正確的代碼 代碼目前有一個問題&#xff0c;主要是在類外部定義成員函數時&#xff0c;不應該…

解密QQ號——C語言

題目&#xff1a; 有一串已加密的數字“6 3 1 7 5 8 9 2 4”解密規則&#xff1a;首先將第1個數字刪除&#xff0c;緊接著將第2個數字放到這串數字的末尾&#xff0c;再將第3個數字刪除并將第4個數字放到這串數字的末尾&#xff0c;再將第5個數刪除 代碼實現&#xff1a; #inc…

利用Node.js和cpolar實現遠程訪問,無需公網IP和路由器設置的完美解決方案

文章目錄 前言1.安裝Node.js環境2.創建node.js服務3. 訪問node.js 服務4.內網穿透4.1 安裝配置cpolar內網穿透4.2 創建隧道映射本地端口 5.固定公網地址 前言 Node.js 是能夠在服務器端運行 JavaScript 的開放源代碼、跨平臺運行環境。Node.js 由 OpenJS Foundation&#xff0…

ESP32網絡編程-OTA方式升級固件(基于Web瀏覽器)

OTA方式升級固件(基于Web瀏覽器) 文章目錄 OTA方式升級固件(基于Web瀏覽器)1、ESP32的OTA介紹2、OTA升級固件方式3、軟件準備4、硬件準備5、代碼實現6、一種優雅方式實現Web方式OTA升級6.1 基礎OTA代碼6.2 新固件庫代碼在前面的文章中,我們在Arduino IDE的網絡端口中,實現…

LeetCode 77.組合

題目&#xff1a; 給定兩個整數 n 和 k&#xff0c;返回范圍 [1, n] 中所有可能的 k 個數的組合。 你可以按 任何順序 返回答案。 方法&#xff1a;靈神-組合型回溯 剪枝 class Solution {private int k;private final List<Integer> path new ArrayList<>();…

反序列化 [網鼎杯 2020 朱雀組]phpweb 1

打開題目 我們發現這個頁面一直在不斷的刷新 我們bp抓包一下看看 我們發現index.php用post方式傳了兩個參數上去&#xff0c;func和p 我們需要猜測func和p兩個參數之間的關系&#xff0c;可以用php函數MD5測一下看看 我們在響應處得到了一串密文&#xff0c;md5解密一下看看 發…

Windows11安裝使用Oracle21C詳細步驟<圖文保姆級>新版本

Windows11安裝使用Oracle21C詳細步驟<圖文保姆級>新版本 Database Software Downloads | Oracle 中國 下載完成后解壓縮 雙擊setup.exe 打開安裝頁面 同意下一步 更改自己的路徑點擊下一步 輸入密碼 下一步安裝等待即可 等待加載配置時間有點久 完成即可 使用 搜索…

【Kubernetes】四層代理Service

Service四層代理 一、Service概念原理1.1、為什么要有Service1.2、Service概述1.3、工作原理1.4、三類IP地址【1】Node Network&#xff08;節點網絡&#xff09;【2】Pod network&#xff08;pod 網絡&#xff09;【3】Cluster Network&#xff08;服務網絡&#xff09; 二、S…