公安部等三部門:平臺不得制定損害外賣騎手等勞動者安全健康的考核指標
(一)概述
1、沒有執行緒池的狀態:
當我們使用一條執行緒的時候,先將執行緒物件創建出來,啟動執行緒,在執行過程中,可能
能完成任務,也可能會在中途被任務內容中斷掉,任務還沒有完成。
即使是能夠正常完成,執行緒物件就結束了,就變成了垃圾物件,需要被垃圾回收器回收
如果在系統中,大量的任務都是小任務,任務消耗時間較短、執行緒物件的建立和消亡耗
費的時間比較多,結果:大部分的時間都浪費在了執行緒物件的建立和死亡上。
如果任務本身破壞力比較大,可能會把執行緒物件結束掉,就無法繼續完成任務。
2、有執行緒池的狀態
在沒有任務的時候,先把執行緒物件準備好,儲存到一個容器中,一旦有任務來的時候,
就不需要建立物件,而是直接將物件獲取出來執行任務
如果任務破壞力較小,任務可以直接完成,這個執行緒物件不會進入死亡狀態,而是被容
器回收,繼續活躍。
如果任務破壞力較大,任務會把執行緒搞死,執行緒池會繼續提供下一個執行緒,繼續完成這
個任務。
(二)使用
1、步驟:獲取執行緒池物件;建立任務類物件;將任務類物件提交到執行緒池中
2、獲取執行緒池物件:
工具類:Executors:生成執行緒池的工具類,根據需求生成指定大小的執行緒池
ExecutorService Executors.newSingleThreadPool():建立一個有單個執行緒的執行緒池
ExecutorService Executors.newFixedThreadPool(int nThreads):建立一個指定線
程數量的執行緒池
3、建立任務類物件:Runnable的實現類物件,用於定義任務內容
4、將任務類物件提交到執行緒池中ExecutorService:是一個介面,不需要手動建立這個介面的實現類物件,使用方法獲取
到的就是這個介面的實現類物件,一定可以呼叫這個介面中的方法
submit(Runnable r):可以將一個任務類物件,提交到執行緒池中,如果有空閒的執行緒,
就可以馬上執行這個任務,如果沒有空閒執行緒,那麼這個任務就需要等待。
shutDown():結束執行緒池,已經提交的全部保證完成,不準繼續提交了
shutDownNow():結束執行緒池,已經開始執行的,保證完成;但是還沒有執行的,已經提
交的,不給運行了,作為返回值範圍;對於沒有提交的,不準提交。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo15_UseThreadPool {
public static void main(String[] args) {
//執行緒池中執行緒的預設名稱:pool-1-thread-1
/*
* 當提交的任務數量多於池中執行緒數,則先給所有執行緒安排任務去執行,哪一個執行緒先執行完了自己的任務,就立馬執行排隊的任務
*
* */
//1.獲取執行緒池:ThreadPoolExecutor
ExecutorService es = Executors.newFixedThreadPool(2);
//2.將任務提交到執行緒池
//submit(Runnable task)
Runnable task1 = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("AAAAAAAAAAAAAAAAA" + Thread.currentThread().getName());
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable task2 = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("@@@@@@@@@@@@@@@@@" + Thread.currentThread().getName());
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable task3 = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("5555555555555555" + Thread.currentThread().getName());
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
es.submit(task1);
es.submit(task2);
es.submit(task3);
//關閉執行緒池,執行已經提交的任務和正在排隊的任務,不接受新任務
es.shutdown();
//關閉執行緒池,嘗試結束正在執行的任務,不執行正在排隊的任務,不接受新任務
//es.shutdownNow();
}
}
執行緒池原理
(一)執行緒池部分體系
1、Executor:介面,定義了一個接收 Runnable 物件的方法executor(Runnable
command)
2、ExecutorService:比 Executor 使用更廣泛的子介面
3、AbstractExecutorService:ExecutorService 抽象方法的實現類
4、ThreadPoolExecutor:執行緒池,可以通過呼叫 Executors 工具類的靜態工廠
方法來建立執行緒池並返回一個 ExecutorService 的實現類物件
(二)ThreadPoolExecutor類概述
1、Executors工具類,是建立執行緒池的工具類
2、ExecutorService介面,是工具類返回執行緒池物件所實現的介面
3、ThreadPoolExecutor是ExecutorService介面的實現類,就是返回的執行緒池對
象所屬類
4、ThreadPoolExecutor的構造方法:
ThreadPoolExecutor(intcorePoolSize,
intmaximumPoolSize, longkeepAliveTime, TimeUnitunit, BlockingQueue<Runnable>workQueue, ThreadFactorythreadFactory,
RejectedExecutionHandlerhandler) 用給定的初始引數建立新的 ThreadPoolExecutor。 |
ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) corePoolSize: 執行緒池的核心執行緒數。在建立了執行緒池後,預設情況下, 執行緒池中並沒有任何執行緒,當有任務來之後,就會建立一個執行緒去執行任務, 當執行緒池中的執行緒數目達到 corePoolSize 後, 就會把到多出的任務放到隊列當中 maximumPoolSize: 執行緒池允許建立的最大執行緒數。 如果佇列滿了,並且已建立的執行緒數小於最大執行緒數, 則執行緒池會再建立新的執行緒執行任務。 注意:如果使用了無界的任務佇列這個引數就沒什麼效果。 keepAliveTime: 執行緒活動保持時間。執行緒池的工作執行緒空閒後,保持存活的時間。 如果任務很多,並且每個任務執行的時間比較短, 可以調大這個時間,提高執行緒的利用率。 unit: 引數 keepAliveTime 的時間單位,在TimeUnit列舉類中,有 7 種取值。 可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES), 毫秒(MILLISECONDS),微秒(MICROSECONDS),納秒(NANOSECONDS) 用來指定keepAliveTime的單位,比如秒:TimeUnit.SECONDS workQueue: 任務佇列。用於儲存等待執行的任務的阻塞佇列。 可以選擇有界佇列和無界佇列 threadFactory: 執行緒工廠,用來建立執行緒。主要是為了給執行緒起名字, 預設工廠的執行緒名字:pool‐1‐thread‐1 Executors工具類中的defaultThreadFactory()方法可以獲取到 用於建立新執行緒的預設執行緒工廠 handler: 拒絕策略,當執行緒池裡執行緒被耗盡,且佇列也滿了的時候會呼叫 |
(三)阻塞佇列和有界、無界佇列
1、阻塞佇列:是一個支援阻塞的插入和移除方法的佇列
(1)支援阻塞的插入方法:當佇列滿時,佇列會阻塞插入元素的執行緒,直
到佇列不滿
(2)支援阻塞的移除方法:當佇列為空時,獲取元素的執行緒會等待佇列變
為非空
2、有界佇列:具有固定大小的佇列,可以進隊的元素個數是有限的。
3、無界佇列:是沒有設定固定大小的佇列。這些佇列的特點是可以直接入列,
直到記憶體資源耗盡
4、相關型別即構造方法:
(1)ArrayBlockingQueue 基於陣列實現的有界阻塞佇列
(2)LinkedBlockingQueue 基於連結串列實現的佇列,可以設定為有界,不設
定則無界
(3)SynchronousQueue 無界無緩衝的佇列,內部容量為零,適用於元素數
量少的場景
(四)拒絕策略
1、ThreadPoolExecutor.AbortPolicy
(此項是預設策略)直接丟擲異常RejectedExecutionException
2、ThreadPoolExecutor.CallerRunsPolicy
該任務被執行緒池拒絕,由呼叫 execute方法的執行緒執行該任務
3、ThreadPoolExecutor.DiscardOldestPolicy
拋棄佇列最前面的任務,然後重新嘗試執行任務
4、ThreadPoolExecutor.DiscardPolicy
丟棄任務,也不會丟擲異常
(五)執行緒池執行流程
(六)有界佇列和無界佇列對執行緒池的影響
1、使用有界佇列:如果有新的任務需要執行,如果執行緒池時機執行緒數量小於核
心執行緒數corePoolSize,則優先建立執行緒。如果大於核心執行緒數corePoolSize,
則會將任務加入佇列。如果佇列已滿,則在匯流排程數量不大於最大執行緒數
maximumPoolSize的前提下,建立新的執行緒。如果執行緒數大於最大執行緒數
maximumPoolSize,則執行拒絕策略
2、使用無界佇列:除了系統資源耗盡,否則無界佇列不存在任務入隊失敗的情
況。當有任務到來,系統的執行緒數小於核心執行緒數corePoolSize時,新建執行緒執
行任務。如果後續仍然有新的任務加入,而沒有空閒的執行緒,則任務直接入隊等
待。如果任務處理慢,而任務新增快,則佇列會快速增長,直到系統資源耗盡。