wordpress geogebraseo刷排名工具
阿華代碼,不是逆風,就是我瘋,
你們的點贊收藏是我前進最大的動力!!希望本文內容能夠幫助到你!
目錄
?
引入:問題引入
一:解決方案
1:方案一——協(xié)程/纖程
(1)本質
2:方案二——線程池
(1)本質
(2)優(yōu)缺點
(3)解釋高效的原因
二:ThreadPoolExecutor(標準庫線程池)
1:Java庫中找
2:構造方法
(1)核心線程數
(2)最大線程數
(3)保持存活時間
(4)時間單位
(5)工作任務
(6)線程工廠
①工廠模式
(7)拒絕策略(面試高頻)
①中止策略
②甩鍋策略
③喜新厭舊
④忠貞不渝
三:Executors(工廠類)
1:.newFixedThreadPool(可以設定固定線程數目)
2:submit添加任務
?編輯3:線程池中線程數量問題
(1)前引
(2)線程任務的分類
①CPU密集型任務
②IO密集型任務
(3)分情況討論
四:通過代碼實現簡單的線程池
1:思路
2:代碼示例
?
引入:問題引入
在之前的學習中,我們了解到,為了降低頻繁創(chuàng)建和銷毀進程所帶來的巨大開銷,我們引入了輕量級進程的概念(線程)
現在若線程的數量進一步提升,那么線程的頻繁創(chuàng)建和銷毀所帶來的資源消耗,我們也不能忽視了
所以我們進行優(yōu)化,引入了“池”的概念:這里有許多種類的池,線程池,數據庫連接池,進程池......(提前把需要用到的對象準備好,用完的 對象也不要直接扔掉,放到池子中以便下次使用)
一:解決方案
1:方案一——協(xié)程/纖程
注:可以理解為輕量級線程
(1)本質
通過用戶態(tài)代碼進行調度,不靠系統(tǒng)內核的調度器調度(節(jié)省了調度的開銷)
注:在java21中“虛擬線程”就是這個意思。
? ? ? ?在用戶代碼中,協(xié)程是基于線程進行封裝的。
? ? ? ?go是比較早支持協(xié)程的,因為語法簡單就火了
2:方案二——線程池
(1)本質
提前創(chuàng)建好線程,需要用的時候直接從池子里拿出來用,用完了也不要釋放而是返還回池子中。
(2)優(yōu)缺點
①優(yōu)點:節(jié)省了創(chuàng)建和銷毀線程帶來的資源消耗,更高效
②缺點:占用了內存空間
(3)解釋高效的原因
從線程池里獲取線程,是在用戶態(tài)代碼中進行調度,是可控的,高效的
從操作系統(tǒng)中獲取線程,是在系統(tǒng)內核中進行完成的,不可控,低效。
二:ThreadPoolExecutor(標準庫線程池)
1:Java庫中找
注:打開網站Overview (Java Platform SE 8 ),找到對應的包和class類
2:構造方法
我們直接看帶有7個參數的構造方法
(1)核心線程數
int corePoolSize
core(核心)pool(池)siz(大小)
?
(2)最大線程數
int maximumPoolSize
核心線程可以理解為公司的正式員工,不能輕易裁掉;
普通線程可以理解為公司的實習生,裁掉比較容易
最大線程數 =? 核心線程數 +普通線程數
(3)保持存活時間
long keepAliveTime
(4)時間單位
TimeUnit unit
單位:s,min,hour.......
普通線程能空閑的最大時間,超過空閑時間限制,就會被移除線程池
還是用上述例子舉例,實習生不能說開就開,假定摸魚時間限制為1個小時,只要實習生摸魚的時間小于1個小時就不會被開,超過就被開
(5)工作任務
BlockingQueue<Runnable>? workQueue
與定時器(上篇文章)相似,線程池可以持有多個任務
Runnable用來描述任務的主體
<>也可以寫PriorityQueue優(yōu)先級隊列
(6)線程工廠
ThreadFactory threadFactory
①工廠模式
通過(“工廠類”)類里面的(不一定是靜態(tài)的)方法,對方法內部的new對象進行構造,完成對象的初始化(相當于,給構造方法外面在套上一層方法——套娃“封裝”)
?
(7)拒絕策略(面試高頻)
RejectedExecutionHandler handler——
execution(執(zhí)行)handler(操作者)
問題:試想,線程池中有一個阻塞隊列,存放的線程數目已經達到最大榮達,這個時候還往里面存放,那么線程池會怎么辦?
①中止策略
.AbortPolicy?——
如果硬要在加新任務的話,線程池:我吃檸檬,lz新舊任務都不干了,拋出異常
②甩鍋策略
.CallerRunsPolicy——
線程池:讓交代給我這個任務的人自己完成這個線程,我才不干
③喜新厭舊
.DiscardOldestPolicy——
discard(丟棄)
線程池拋棄池中呆的最久最老的一個線程,迎接新歡(喜新厭舊)
④忠貞不渝
.DiscardPolicy——
丟棄要新添加的任務,繼續(xù)我行我素執(zhí)行線程池中本來就有的任務
三:Executors(工廠類)
因為ThreadPoolExecutor使用起來較為復雜,所以標準庫中就封裝了一下,提供了Executors這個版本(工廠類,在內部把ThreadPoolExecutor創(chuàng)建好了,并且設置了不同的參數)
1:.newFixedThreadPool(可以設定固定線程數目)
2:submit添加任務
package thread;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadDemon34 {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(4);service.submit(new Runnable(){@Overridepublic void run() {System.out.println("執(zhí)行線程池中第一個任務");}});}
}
返回值類型點進去
3:線程池中線程數量問題
(1)前引
我們知道,線程的運行效率,跟cpu的邏輯核心數直接相關,假設cpu的邏輯核心數為N,那線程的數量該是多少合適(2N?1.5N?N?..........)
(2)線程任務的分類
①CPU密集型任務
線程大部分時間都在CPU上運行,計算
②IO密集型任務
大部分時間都在等待IO(input,output)。例如:Scanner讀取用戶的輸入
(3)分情況討論
到底在線程池中添加多少線程數量合適呢?
如果線程多為CPU類型的,那線程數目盡量不要超過N
如果線程多為IO類型的,那線程數目就可以遠遠超過N
但是具體開發(fā)肯定是需要我們多次測試,通過觀察系統(tǒng)資源消耗,來找出最合適的添加數目的。
四:通過代碼實現簡單的線程池
1:思路
大邏輯其實就是,把創(chuàng)建的任務提交上去,再把任務取出來,在run執(zhí)行就可以了就是這么簡單
我們用到的IDEA自帶的順序表,阻塞隊列BlockingQueue都其實是一個工具罷了~~
2:代碼示例
package thread;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;/*** Created with IntelliJ IDEA.* Description:* User: Hua YY* Date: 2024-09-27* Time: 16:48*/class MyThreadPoolExecutor{//2:創(chuàng)建一個順序表來接收創(chuàng)建的線程private List<Thread> threadList = new ArrayList<>();//4創(chuàng)建一個容量合適的阻塞隊列private BlockingQueue<Runnable> queue = new ArrayBlockingQueue(1000);//1:通過一個循環(huán),n的值,來控制產生的線程的數量public MyThreadPoolExecutor(int n){for (int i = 0; i < n; i++) {Thread t = new Thread(()->{//6:把要做的任務從任務隊列中不停地取出來,并且執(zhí)行while(true){try {//帶有阻塞的take取出元素Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();//3:threadList.add(t);}}//5:提交runnable到隊列里面去public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}
}
public class ThreadDemon35 {//大邏輯其實就是,把創(chuàng)建的任務提交上去,再把任務取出來,在run執(zhí)行就可以了就是這么簡單public static void main(String[] args) throws InterruptedException {MyThreadPoolExecutor executor = new MyThreadPoolExecutor(4);for (int i = 0 ; i < 1000 ; i++){//變量捕獲int n = i;executor.submit(new Runnable() {@Overridepublic void run() {System.out.println("執(zhí)行任務:" + n + " " + "當前線程為:" + Thread.currentThread().getName());}});}}
}
?