ThreadPool執行緒池
ThreadPool執行緒池
為什麼要用執行緒池
例子:10年前單核CPU電腦,假的多執行緒,像馬戲團小丑玩多個球,CPU需要來回切換。現在是多核電腦,多個執行緒各自跑在獨立的CPU上,不用切換,效率高。
執行緒池的優勢: 執行緒池做的工作只要是控制執行的執行緒數量,處理過程中將任務放入佇列,然後線上程建立後啟動這些任務,如果執行緒數量超過了最大數量,超出數量的執行緒排隊等候,等其他執行緒執行完畢,再從佇列中取出任務來執行。
它的主要特點為:執行緒複用;控制最大併發數;管理執行緒。
第一: 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的銷耗。
第二: 提高響應速度。當任務到達時,任務可以不需要等待執行緒建立就能立即執行。
第三: 提高執行緒的可管理性。執行緒是稀缺資源,如果無限制的建立,不僅會銷耗系統資源,還會降低系統的穩定性,使用執行緒池可以進行統一的分配,調優和監控。
執行緒池如何使用
架構說明:
Java中的執行緒池是通過Executor框架實現的,該框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor這幾個類。
編碼實現:
①
Executors.newFixedThreadPool(int)
執行長期任務效能好,建立一個執行緒池,
一池有N個固定的執行緒,有固定執行緒數的執行緒
newFixedThreadPool建立的執行緒池corePoolSize和maximumPoolSize值是相等的,它使用的是LinkedBlockingQueue
public static ExecutorService newFixedThreadPool (int nThreads){
return new ThreadPoolExecutor(nThreads,
nThreads,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
②
Executors.newSingleThreadExecutor()
一個任務一個任務的執行,一池一執行緒
newSingleThreadExecutor 建立的執行緒池corePoolSize和maximumPoolSize值都是1,它使用的是LinkedBlockingQueue
public static ExecutorService newSingleThreadExecutor () {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(
1,
1,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
③
Executors.newCachedThreadPool()
執行很多短期非同步任務,執行緒池根據需要建立新執行緒,
但在先前構建的執行緒可用時將重用它們。可擴容,遇強則強
newCachedThreadPool建立的執行緒池將corePoolSize設定為0,將maximumPoolSize設定為Integer.MAX_VALUE,它使用的是SynchronousQueue,也就是說來了任務就建立執行緒執行,當執行緒空閒超過60秒,就銷燬執行緒。
public static ExecutorService newCachedThreadPool () {
return new ThreadPoolExecutor(
0,
Integer.MAX_VALUE,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
執行緒池7大重要引數
部分原始碼:
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
1、corePoolSize:執行緒池中的常駐核心執行緒數
2、maximumPoolSize:執行緒池中能夠容納同時
執行的最大執行緒數,此值必須大於等於1
3、keepAliveTime:多餘的空閒執行緒的存活時間
當前池中執行緒數量超過corePoolSize時,當空閒時間
達到keepAliveTime時,多餘執行緒會被銷燬直到
只剩下corePoolSize個執行緒為止
4、unit:keepAliveTime的單位
5、workQueue:任務佇列,被提交但尚未被執行的任務
6、threadFactory:表示生成執行緒池中工作執行緒的執行緒工廠,
用於建立執行緒,一般預設的即可
7、handler:拒絕策略,表示當佇列滿了,並且工作執行緒大於
等於執行緒池的最大執行緒數(maximumPoolSize)時如何來拒絕
請求執行的runnable的策略
執行緒池底層工作原理
1、在建立了執行緒池後,開始等待請求。
2、當呼叫execute()方法新增一個請求任務時,執行緒池會做出如下判斷:
2.1如果正在執行的執行緒數量小於corePoolSize,那麼馬上建立執行緒執行這個任務;
2.2如果正在執行的執行緒數量大於或等於corePoolSize,那麼將這個任務放入佇列;
2.3如果這個時候佇列滿了且正在執行的執行緒數量還小於maximumPoolSize,那麼還是要建立非核心執行緒立刻執行這個任務;
2.4如果佇列滿了且正在執行的執行緒數量大於或等於maximumPoolSize,那麼執行緒池會啟動飽和拒絕策略來執行。
3、當一個執行緒完成任務時,它會從佇列中取下一個任務來執行。
4、當一個執行緒無事可做超過一定的時間(keepAliveTime)時,執行緒會判斷: 如果當前執行的執行緒數大於corePoolSize,那麼這個執行緒就被停掉。 所以執行緒池的所有任務完成後,它最終會收縮到corePoolSize的大小。
圖解示例:
執行緒池用哪個?生產中如設定合理引數
執行緒池的拒絕策略
是什麼
等待佇列已經排滿了,再也塞不下新任務了同時,執行緒池中的max執行緒也達到了,無法繼續為新任務服務。這個是時候我們就需要拒絕策略機制合理的處理這個問題。
JDK內建的拒絕策略
AbortPolicy(預設) | CallerRunsPolicy | DiscardOldestPolicy | DiscardPolicy |
---|---|---|---|
直接丟擲RejectedExecutionException異常阻止系統正常執行 | “呼叫者執行”一種調節機制,該策略既不會拋棄任務,也不會丟擲異常,而是將某些任務回退到呼叫者,從而降低新任務的流量。 | 拋棄佇列中等待最久的任務,然後把當前任務加人佇列中嘗試再次提交當前任務。 | 該策略默默地丟棄無法處理的任務,不予任何處理也不丟擲異常。如果允許任務丟失,這是最好的一種策略。 |
以上內建拒絕策略均實現了RejectedExecutionHandle介面
在工作中單一的/固定數的/可變的三種建立執行緒池的方法哪個用的多?超級大坑
答案是一個都不用,我們工作中只能使用自定義的
Executors中JDK已經給你提供了,為什麼不用?
如何自定義 見下面的程式碼
程式碼
package cduck.cn;
import java.util.concurrent.*;
public class MyThreadPoolDemo {
public static void main(String[] args) {
//電腦CPU數量
System.out.println(Runtime.getRuntime().availableProcessors());
//一池5個工作執行緒。類似一個銀行有5個受理視窗
// ExecutorService threadPool= Executors.newFixedThreadPool(5);
// 一池1個工作執行緒,類似一個銀行有1個受理視窗
// ExecutorService threadPool= Executors.newSingleThreadExecutor();
//一池N個工作執行緒,類似一個銀行N個視窗--自動擴容
// ExecutorService threadPool= Executors.newCachedThreadPool();
//自定義的執行緒池
ExecutorService threadPool= new ThreadPoolExecutor(
2,
5,
2L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
try{
//模擬銀行有10個顧客來辦理銀行業務,目前池子裡有5個工作人員提供服務
for (int i=0;i<20;i++){
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t 辦理業務");
});
// TimeUnit.SECONDS.sleep(1);
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
相關文章
- Java-ThreadPool執行緒池總結Javathread執行緒
- Java核心(二)深入理解執行緒池ThreadPoolJava執行緒thread
- .NET Core 執行緒池(ThreadPool)底層原理淺談執行緒thread
- rust 實戰 - 實現一個執行緒工作池 ThreadPoolRust執行緒thread
- 美團面試題:Java-執行緒池 ThreadPool 專題詳解面試題Java執行緒thread
- Java執行緒池二:執行緒池原理Java執行緒
- 執行緒和執行緒池執行緒
- 執行緒 執行緒池 Task執行緒
- 多執行緒【執行緒池】執行緒
- 執行緒池執行緒
- 執行緒池以及四種常見執行緒池執行緒
- java執行緒池趣味事:這不是執行緒池Java執行緒
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- 二. 執行緒管理之執行緒池執行緒
- Android多執行緒之執行緒池Android執行緒
- kuangshenshuo-多執行緒-執行緒池執行緒
- 多執行緒之手撕執行緒池執行緒
- java多執行緒9:執行緒池Java執行緒
- 執行緒池管理(1)-為什麼需要執行緒池執行緒
- Android執行緒池Android執行緒
- java 執行緒池Java執行緒
- Java執行緒池Java執行緒
- 執行緒池 Executor執行緒
- 執行緒與執行緒池的那些事之執行緒池篇(萬字長文)執行緒
- 執行緒池之ScheduledThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- 執行緒池之ThreadPoolExecutor執行緒池原始碼分析筆記執行緒thread原始碼筆記
- SpringBoot執行緒池和Java執行緒池的實現原理Spring Boot執行緒Java
- Android程式框架:執行緒與執行緒池Android框架執行緒
- 執行緒池建立執行緒的過程執行緒
- 【Java】【多執行緒】執行緒池簡述Java執行緒
- Java執行緒池一:執行緒基礎Java執行緒
- Java多執行緒-執行緒池的使用Java執行緒
- golang workpool,工作池,執行緒池Golang執行緒
- Python執行緒池與程式池Python執行緒
- 原始碼|從序列執行緒封閉到物件池、執行緒池原始碼執行緒物件
- Netty原始碼解析一——執行緒池模型之執行緒池NioEventLoopGroupNetty原始碼執行緒模型OOP
- 執行緒(一)——執行緒,執行緒池,Task概念+程式碼實踐執行緒
- 多執行緒系列(三):執行緒池基礎執行緒