執行緒池 一、executor介面和ExecutorService介面介紹
工作這麼多年,很少有時間寫部落格,昨天和一個正在跳槽找工作的同學交流,他是做web的,面試的時候被問到了執行緒池一塊的技術,被難住了!這讓我不禁也想鞏固下我這方便的基礎了,天天在用的東西,尤其是像我們這種做網際網路服務端開發的,高併發處理中建立一個優異Thread Pool對執行緒進行復用還是很重要的!俗話說好記性不如爛筆頭,先介紹下Executor介面吧!
為什麼需要建立執行緒池:
(1)因為伺服器如果每一個請求都會建立一個新執行緒,會導致效能上的瓶頸,因為執行緒建立和銷燬都需要jvm不停的處理,如果一個執行緒執行的時間 < (執行緒建立時間+執行緒銷燬的時間)的時候,我們就要考慮執行緒的複用了!
(2)、執行緒數量建立過多,沒有有效的管理,反而起到的是副作用,會大大降低系統的效能的!
(3)、我們要根據具體的業務需求不同,結合作業系統的處理器CPU核數,能夠合理的控制執行緒池大小!選擇不同策略的執行緒池,盲目使用也會帶來一定風險,比如記憶體洩漏,死鎖,併發問題.....
執行緒池的好處:
(1)、降低資源消耗:執行緒複用。
(2)、提高響應速度:有任務的時候,不需要去等待建立執行緒,直接使用已有的執行緒;
(3)、管理:執行緒池對執行緒進行統一分配,調優,監控等等;
一、Executor 介面 (友情提示:不是類Executors)
執行緒與Executor框架執行緒,作業系統各自扮演的角色:任務的2級排程
java.util.concurrent.Executor: 大部分執行緒池相關的介面都是實現這個介面的
public interface Executor {
void execute(Runnable command);
}
他的子介面和實現的類如下:
完整的Executor介面繼承實現結構圖如下:
我們重點看我圈出來的不分,基本就是你學習執行緒池這塊要反覆看的內容;
我們繼續順著原始碼往下分析:(綠色實線箭頭是繼承,虛線是介面實現)
1、ExecutorService:servirce顧名思義是提供服務的介面。
【首先申明executor架構下的ForkJoinPool思想和其他的介面類不一樣,ForkJoinPool的優勢在於,可以充分利用多cpu,多核cpu的優勢,把一個任務拆分成多個“小任務”,把多個“小任務”放到多個處理器核心上並行執行;當多個“小任務”執行完成之後,再將這些執行結果合併起來;(後續具體介紹ForkJoinPool用法)】;
(1)shutdown: 具體原始碼實現是:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//想操作shutdown和shutdownnow許可權check ModifyThread許可權通過
checkShutdownAccess();
//將runstate設為給定的目標
advanceRunState(SHUTDOWN);
//中斷一些正在等待任務的的空閒的執行緒,
interruptIdleWorkers();
//取消和清楚,由於shutdown策略中所有不應該繼續執行的工作佇列
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
下面我謝的一個簡單的test:
總結:shutdown 呼叫之後,執行緒池拒絕接受新submit的任務,但是會繼續執行在shutdown之前的任務;
(2)、shutdownNow:原始碼相似,他是停止正在執行的任務,返回空閒的執行緒,並且拒絕接受新的任務
(3)、isShutdown():當前executor是否已經shutdown
(4)、isTerminated();若關閉後所有任務都已完成,則返回true。注意除非首先呼叫shutdown或shutdownNow,否則isTerminated永不為true;
(6)、submit():提交新的任務,任務分Runnable和Callable型別
(7)、invokeAll()和invokeAny(),在批量執行或多選一的業務場景中非常方便。invokeAll()在所有任務都完成(包括成功/被中斷/超時)後才會返回,invokeAny()在任意一個任務成功(或ExecutorService被中斷/超時)後就會返回。
package com.executor.test;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:
* User: ZhuRong
* Date: 2018-07-20 13:18
*/
public class ShutDowmTest {
static int index = 1;
public static void main(String[] args) {
try {
//建立一個執行緒池,可以同一時間容乃3條執行緒
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new AutoIncressNum());
}
Thread.sleep(2000L);
executorService.shutdown();
for (int i = 0; i < 3; i++) {
executorService.submit(new AutoIncressNum());
}
System.out.println(executorService.isShutdown());
System.out.println(executorService.isTerminated());
} catch (Exception e) {
e.printStackTrace();
}
}
static class AutoIncressNum implements Runnable {
@Override
public void run() {
try {
Random random = new Random();
Thread.sleep(1000L + random.nextInt(5000));
System.out.println(Thread.currentThread().getName()+":"+index);
index++;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName() + " Interrupted!");
e.printStackTrace();
}
}
}
}
package com.executor.test;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Description:
* User: ZhuRong
* Date: 2018-07-20 13:18
*/
public class ShutDownNowTest {
static int index = 1;
public static void main(String[] args) {
try {
//建立一個執行緒池,可以同一時間容乃3條執行緒
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new AutoIncressNum());
}
Thread.sleep(2000L);
List<Runnable> list = executorService.shutdownNow();
System.out.println(executorService.isShutdown());
System.out.println(executorService.isTerminated());
for(Runnable l: list){
System.out.println(l.toString());
}
for (int i = 0; i < 2; i++) {
executorService.submit(new AutoIncressNum());
}
} catch (Exception e) {
// e.printStackTrace();
}
}
static class AutoIncressNum implements Runnable {
@Override
public void run() {
try {
Random random = new Random();
Thread.sleep(1000L + random.nextInt(5000));
System.out.println(Thread.currentThread().getName()+":"+index);
index++;
} catch (Exception e) {
System.out.println(Thread.currentThread().getName() + " Interrupted!");
e.printStackTrace();
}
}
}
}
先介紹這2個介面,後面有時間繼續介紹其他的執行緒池相關的介面和類!這個測試案例建議和大家還是跑一跑就懂了ExecutorService這一個介面的裡面的api應用了!