一、執行緒
1、什麼是執行緒
執行緒(thread)是作業系統能夠進行運算排程的最小單位。它被包含在程式之中,是程式中的實際 運作單位。一條執行緒指的是程式中一個單一順序的控制流,一個程式中可以併發多個執行緒,每條線 程並行執行不同的任務。
2、如何建立執行緒
2.1、JAVA中建立執行緒
/**
* 繼承Thread類,重寫run方法
*/
class MyThread extends Thread {
@Override
public void run() {
System.out.println("myThread..." + Thread.currentThread().getName());
} }
/**
* 實現Runnable介面,實現run方法
*/
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable..." + Thread.currentThread().getName());
} }
/**
* 實現Callable介面,指定返回型別,實現call方法
*/
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "MyCallable..." + Thread.currentThread().getName();
} }
2.2、測試一下
public static void main(String[] args) throws Exception {
MyThread thread = new MyThread();
thread.run(); //myThread...main
thread.start(); //myThread...Thread-0
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable);
myRunnable.run(); //MyRunnable...main
thread1.start(); //MyRunnable...Thread-1
MyCallable myCallable = new MyCallable();
FutureTask<String> futureTask = new FutureTask<>(myCallable);
Thread thread2 = new Thread(futureTask);
thread2.start();
System.out.println(myCallable.call()); //MyCallable...main
System.out.println(futureTask.get()); //MyCallable...Thread-2
}
2.3、問題
既然我們建立了執行緒,那為何我們直接呼叫方法和我們呼叫start()方法的結果不同?new Thread() 是否真實建立了執行緒?
2.4、問題分析
我們直接呼叫方法,可以看到是執行的主執行緒,而呼叫start()方法就是開啟了新執行緒,那說明new Thread()並沒有建立執行緒,而是在start()中建立了執行緒。
那我們看下Thread類start()方法:
class Thread implements Runnable { //Thread類實現了Runnalbe介面,實現了run()方法
private Runnable target;
public synchronized void start() {
...
boolean started = false;
try {
start0(); //可以看到,start()方法真實的呼叫時start0()方法
started = true;
} finally {
...
}
}
private native void start0(); //start0()是一個native方法,由JVM呼叫底層作業系統,開啟一個執行緒,由作業系統過統一排程
@Override
public void run() {
if (target != null) {
target.run(); //作業系統在執行新開啟的執行緒時,回撥Runnable介面的run()方法,執行我們預設的執行緒任務
}
}
}
2.5、總結
- JAVA不能直接建立執行緒執行任務,而是透過建立Thread物件呼叫作業系統開啟執行緒,在由操作系 統回撥Runnable介面的run()方法執行任務;
- 實現Runnable的方式,將執行緒實際要執行的回撥任務單獨提出來了,實現執行緒的啟動與回撥任務 解耦;
- 實現Callable的方式,透過Future模式不但將執行緒的啟動與回撥任務解耦,而且可以在執行完成後 獲取到執行的結果;
二、多執行緒
1、什麼是多執行緒
多執行緒(multithreading),是指從軟體或者硬體上實現多個執行緒併發執行的技術。同一個執行緒只 能處理完一個任務在處理下一個任務,有時我們需要多個任務同時處理,這時,我們就需要建立多 個執行緒來同時處理任務。
2、多執行緒有什麼好處
2.1、序列處理
public static void main(String[] args) throws Exception {
System.out.println("start...");
long start = System.currentTimeMillis();
for (int i = 0; i < 5; i++) {
Thread.sleep(2000); //每個任務執行2秒
System.out.println("task done..."); //處理執行結果
}
long end = System.currentTimeMillis();
System.out.println("end...,time = " + (end - start));
}
//執行結果
start...
task done...
task done...
task done...
task done...
task done... end...,time = 10043
2.2、並行處理
public static void main(String[] args) throws Exception {
System.out.println("start...");
long start = System.currentTimeMillis();
List<Future> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(2000); //每個任務執行2秒
return "task done...";
}
};
FutureTask task = new FutureTask(callable);
list.add(task);
new Thread(task).start();
}
list.forEach(future -> {
try {
System.out.println(future.get()); //處理執行結果 } catch (Exception e) {
}
});
long end = System.currentTimeMillis();
System.out.println("end...,time = " + (end - start));
}
//執行結果
start...
task done...
task done...
task done...
task done...
task done... end...,time = 2005
2.3、總結
- 多執行緒可以把一個任務拆分為幾個子任務,多個子任務可以併發執行,每一個子任務就是一個執行緒。
- 多執行緒是為了同步完成多項任務,不是為了提高執行效率,而是為了提高資源使用效率來提高系統 的效率。
2.4、多執行緒的問題
上面示例中我們可以看到,如果每來一個任務,我們就建立一個執行緒,有很多工的情況下,我們 會建立大量的執行緒,可能會導致系統資源的耗盡。同時,我們知道執行緒的執行是需要搶佔CPU資源 的,那如果有太多的執行緒,就會導致大量時間用線上程切換的開銷上。
再有,每來一個任務都需要建立一個執行緒,而建立一個執行緒需要呼叫作業系統底層方法,開銷較 大,而執行緒執行完成後就被回收了。在需要大量執行緒的時候,建立執行緒的時間就花費不少了。
三、執行緒池
1、如何設計一個執行緒池
由於多執行緒的開發存在上述的一些問題,那我們是否可以設計一個東西來避免這些問題呢?當然可以! 執行緒池就是為了解決這些問題而生的。那我們該如何設計一個執行緒池來解決這些問題呢?或者說,一個執行緒池該具備什麼樣的功能?
1.1、執行緒池基本功能
- 多執行緒會建立大量的執行緒耗盡資源,那執行緒池應該對執行緒數量有所限制,可以保證不會耗盡系統資 源;
- 每次建立新的執行緒會增加建立時的開銷,那執行緒池應該減少執行緒的建立,儘量複用已建立好的線 程;
1.2、執行緒池面臨問題
- 我們知道執行緒在執行完自己的任務後就會被回收,那我們如何複用執行緒?
- 我們指定了執行緒的最大數量,當任務數超出執行緒數時,我們該如何處理?
1.3、創新源於生活
先假設一個場景:假設我們是一個物流公司的管理人員,要配送的貨物就是我們的任務,貨車就是 我們配送工具,我們當然不能有多少貨物就準備多少貨車。那當顧客源源不斷的將貨物交給我們配 送,我們該如何管理才能讓公司經營的最好呢?
- 最開始貨物來的時候,我們還沒有貨車,每批要運輸的貨物我們都要購買一輛車來運輸;
- 當貨車運輸完成後,暫時還沒有下一批貨物到達,那貨車就在倉庫停著,等有貨物來了立馬就可以 運輸;
- 當我們有了一定數量的車後,我們認為已經夠用了,那後面就不再買車了,這時要是由新的貨物來 了,我們就會讓貨物先放倉庫,等有車回來在配送;
- 當618大促來襲,要配送的貨物太多,車都在路上,倉庫也都放滿了,那怎麼辦呢?我們就選擇臨 時租一些車來幫忙配送,提高配送的效率;
- 但是貨物還是太多,我們增加了臨時的貨車,依舊配送不過來,那這時我們就沒辦法了,只能讓發 貨的客戶排隊等候或者乾脆不接受了;
- 大促圓滿完成後,累計的貨物已經配送完成了,為了降低成本,我們就將臨時租的車都還了;
1.4、技術源於創新
基於上述場景,物流公司就是我們的執行緒池、貨物就是我們的執行緒任務、貨車就是我們的執行緒。我 們如何設計公司的管理貨車的流程,就應該如何設計執行緒池管理執行緒的流程。
- 當任務進來我們還沒有執行緒時,我們就該建立執行緒執行任務;
- 當執行緒任務執行完成後,執行緒不釋放,等著下一個任務進來後接著執行;
- 當建立的執行緒數量達到一定量後,新來的任務我們存起來等待空閒執行緒執行,這就要求執行緒池有個 存任務的容器;
- 當容器存滿後,我們需要增加一些臨時的執行緒來提高處理效率;
- 當增加臨時執行緒後依舊處理不了的任務,那就應該將此任務拒絕;
- 當所有任務執行完成後,就應該將臨時的執行緒釋放掉,以免增加不必要的開銷;
2、執行緒池具體分析
上文中,我們講了該如何設計一個執行緒池,下面我們看看大神是如何設計的;
2.1、 JAVA中的執行緒池是如何設計的
2.1.1、 執行緒池設計
看下執行緒池中的屬性,瞭解執行緒池的設計。
public class ThreadPoolExecutor extends AbstractExecutorService {
//執行緒池的打包控制狀態,用高3位來表示執行緒池的執行狀態,低29位來表示執行緒池中工作執行緒的數量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//值為29,用來表示偏移量
private static final int COUNT_BITS = Integer.SIZE - 3;
//執行緒池的最大容量
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
//執行緒池的執行狀態,總共有5個狀態,用高3位來表示
private static final int RUNNING = -1 << COUNT_BITS; //接受新任務並處理阻塞佇列中的任務
private static final int SHUTDOWN = 0 << COUNT_BITS; //不接受新任務但會處理阻塞佇列中的任務
private static final int STOP = 1 << COUNT_BITS; //不會接受新任務,也不會處理阻塞佇列中的任務,並且中斷正在執行的任務
private static final int TIDYING = 2 << COUNT_BITS; //所有任務都已終止, 工作執行緒數量為0,即將要執行terminated()鉤子方法
private static final int TERMINATED = 3 << COUNT_BITS; // terminated()方法已經執行結束
//任務快取佇列,用來存放等待執行的任務
private final BlockingQueue<Runnable> workQueue;
//全域性鎖,對執行緒池狀態等屬性修改時需要使用這個鎖
private final ReentrantLock mainLock = new ReentrantLock();
//執行緒池中工作執行緒的集合,訪問和修改需要持有全域性鎖
private final HashSet<Worker> workers = new HashSet<Worker>();
// 終止條件
private final Condition termination = mainLock.newCondition();
//執行緒池中曾經出現過的最大執行緒數
private int largestPoolSize;
//已完成任務的數量
private long completedTaskCount;
//執行緒工廠
private volatile ThreadFactory threadFactory;
//任務拒絕策略
private volatile RejectedExecutionHandler handler;
//執行緒存活時間
private volatile long keepAliveTime;
//是否允許核心執行緒超時
private volatile boolean allowCoreThreadTimeOut;
//核心池大小,若allowCoreThreadTimeOut被設定,核心執行緒全部空閒超時被回收的情況下會為0
private volatile int corePoolSize;
//最大池大小,不得超過CAPACITY
private volatile int maximumPoolSize;
//預設的任務拒絕策略
private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();
//執行許可權相關
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
...
}
小結一下:以上執行緒池的設計可以看出,執行緒池的功能還是很完善的。
- 提供了執行緒建立、數量及存活時間等的管理;
- 提供了執行緒池狀態流轉的管理;
- 提供了任務快取的各種容器;
- 提供了多餘任務的處理機制;
- 提供了簡單的統計功能;
2.1.2、執行緒池建構函式
//建構函式
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;
}
小結一下:
- 建構函式告訴了我們可以怎樣去適用執行緒池,執行緒池的哪些特性是我們可以控制的;
2.1.3、執行緒池執行
2.1.3.1、提交任務方法
• public void execute(Runnable command);
• Future<?> submit(Runnable task);
• Future submit(Runnable task, T result);
• Future submit(Callable task);
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
可以看到submit方法的底層呼叫的也是execute方法,所以我們這裡只分析execute方法;
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//第一步:建立核心執行緒
if (workerCountOf(c) < corePoolSize) { //worker數量小於corePoolSize
if (addWorker(command, true)) //建立worker
return;
c = ctl.get();
}
//第二步:加入快取佇列
if (isRunning(c) && workQueue.offer(command)) { //執行緒池處於RUNNING狀態,將任務加入workQueue任務快取佇列
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command)) //雙重檢查,若執行緒池狀態關閉了,移除任務
reject(command);
else if (workerCountOf(recheck) == 0) //執行緒池狀態正常,但是沒有執行緒了,建立worker
addWorker(null, false);
}
//第三步:建立臨時執行緒
else if (!addWorker(command, false))
reject(command);
}
小結一下:execute()方法主要功能:
- 核心執行緒數量不足就建立核心執行緒;
- 核心執行緒滿了就加入快取佇列;
- 快取佇列滿了就增加非核心執行緒;
- 非核心執行緒也滿了就拒絕任務;
2.1.3.2、建立執行緒
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
//等價於:rs>=SHUTDOWN && (rs != SHUTDOWN || firstTask != null || workQueue.isEmpty())
//執行緒池已關閉,並且無需執行快取佇列中的任務,則不建立
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c)) //CAS增加執行緒數
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
//上面的流程走完,就可以真實開始建立執行緒了
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask); //這裡建立了執行緒
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w); //這裡將執行緒加入到執行緒池中
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //新增成功,啟動執行緒
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w); //新增執行緒失敗操作
}
return workerStarted;
}
小結:addWorker()方法主要功能;
- 增加執行緒數;
- 建立執行緒Worker例項加入執行緒池;
- 加入完成開啟執行緒;
- 啟動失敗則回滾增加流程;
2.1.3.3、工作執行緒的實現
private final class Worker //Worker類是ThreadPoolExecutor的內部類
extends AbstractQueuedSynchronizer
implements Runnable
{
final Thread thread; //持有實際執行緒
Runnable firstTask; //worker所對應的第一個任務,可能為空
volatile long completedTasks; //記錄執行任務數
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this); //當前執行緒呼叫ThreadPoolExecutor中的runWorker方法,在這裡實現的執行緒複用
}
...繼承AQS,實現了不可重入鎖...
}
小結:工作執行緒Worker類主要功能;
- 此類持有一個工作執行緒,不斷處理拿到的新任務,持有的執行緒即為可複用的執行緒;
- 此類可看作一個適配類,在run()方法中真實呼叫runWorker()方法不斷獲取新任務,完成執行緒複用;
2.1.3.4、執行緒的複用
final void runWorker(Worker w) { //ThreadPoolExecutor中的runWorker方法,在這裡實現的執行緒複用
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true; //標識執行緒是否異常終止
try {
while (task != null || (task = getTask()) != null) { //這裡會不斷從任務佇列獲取任務並執行
w.lock();
//執行緒是否需要中斷
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task); //執行任務前的Hook方法,可自定義
Throwable thrown = null;
try {
task.run(); //執行實際的任務
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown); //執行任務後的Hook方法,可自定義
}
} finally {
task = null; //執行完成後,將當前執行緒中的任務制空,準備執行下一個任務
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly); //執行緒執行完成後的清理工作
}
}
小結:runWorker()方法主要功能;
- 迴圈從快取佇列中獲取新的任務,直到沒有任務為止;
- 使用worker持有的執行緒真實執行任務;
- 任務都執行完成後的清理工作;
2.1.3.5、佇列中獲取待執行任務
private Runnable getTask() {
boolean timedOut = false; //標識當前執行緒是否超時未能獲取到task物件
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) //若執行緒存活時間超時,則CAS減去執行緒數量
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //允許超時回收則阻塞等待
workQueue.take(); //不允許則直接獲取,沒有就返回null
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
小結:getTask()方法主要功能;
- 實際在快取佇列中獲取待執行的任務;
- 在這裡管理執行緒是否要阻塞等待,控制執行緒的數量;
2.1.3.6、清理工作
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w); //移除執行完成的執行緒
} finally {
mainLock.unlock();
}
tryTerminate(); //每次回收完一個執行緒後都嘗試終止執行緒池
int c = ctl.get();
if (runStateLessThan(c, STOP)) { //到這裡說明執行緒池沒有終止
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false); //異常終止執行緒的話,需要在常見一個執行緒
}
}
小結:processWorkerExit()方法主要功能;
- 真實完成執行緒池執行緒的回收;
- 呼叫嘗試終止執行緒池;
- 保證執行緒池正常執行;
2.1.3.7、嘗試終止執行緒池
final void tryTerminate() {
for (;;) {
int c = ctl.get();
//若執行緒池正在執行、執行緒池已終止、執行緒池還需要執行快取佇列中的任務時,返回
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
//執行到這裡,執行緒池為SHUTDOWN且無待執行任務 或 STOP 狀態
if (workerCountOf(c) != 0) {
interruptIdleWorkers(ONLY_ONE); //只中斷一個執行緒
return;
}
//執行到這裡,執行緒池已經沒有可用執行緒了,可以終止了
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { //CAS設定執行緒池終止
try {
terminated(); //執行鉤子方法
} finally {
ctl.set(ctlOf(TERMINATED, 0)); //這裡將執行緒池設為終態
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
小結:tryTerminate()方法主要功能;
- 實際嘗試終止執行緒池;
- 終止成功則呼叫鉤子方法,並且將執行緒池置為終態。
2.2、JAVA執行緒池總結
以上透過對JAVA執行緒池的具體分析我們可以看出,雖然流程看似複雜,但其實有很多內容都是狀態重複校驗、執行緒安全的保證等內容,其主要的功能與我們前面所提出的設計功能一致,只是額外增加了一些擴充套件,下面我們簡單整理下執行緒池的功能;
2.2.1、主要功能
- 執行緒數量及存活時間的管理;
- 待處理任務的儲存功能;
- 執行緒複用機制功能;
- 任務超量的拒絕功能;
2.2.2、擴充套件功能
- 簡單的執行結果統計功能;
- 提供執行緒執行異常處理機制;
- 執行前後處理流程自定義;
- 提供執行緒建立方式的自定義;
2.2.3、流程總結
以上透過對JAVA執行緒池任務提交流程的分析我們可以看出,執行緒池執行的簡單流程如下圖所示;
2.3、JAVA執行緒池使用
執行緒池基本使用驗證上述流程:
public static void main(String[] args) throws Exception {
//建立執行緒池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5, 10, 100, TimeUnit.SECONDS, new ArrayBlockingQueue(5));
//加入4個任務,小於核心執行緒,應該只有4個核心執行緒,佇列為0
for (int i = 0; i < 4; i++) {
threadPoolExecutor.submit(new MyRunnable());
}
System.out.println("worker count = " + threadPoolExecutor.getPoolSize()); //worker count = 4
System.out.println("queue size = " + threadPoolExecutor.getQueue().size()); //queue size = 0
//再加4個任務,超過核心執行緒,但是沒有超過核心執行緒 + 快取佇列容量,應該5個核心執行緒,佇列為3
for (int i = 0; i < 4; i++) {
threadPoolExecutor.submit(new MyRunnable());
}
System.out.println("worker count = " + threadPoolExecutor.getPoolSize()); //worker count = 5
System.out.println("queue size = " + threadPoolExecutor.getQueue().size()); //queue size = 3
//再加4個任務,佇列滿了,應該5個熱核心執行緒,佇列5個,非核心執行緒2個
for (int i = 0; i < 4; i++) {
threadPoolExecutor.submit(new MyRunnable());
}
System.out.println("worker count = " + threadPoolExecutor.getPoolSize()); //worker count = 7
System.out.println("queue size = " + threadPoolExecutor.getQueue().size()); //queue size = 5
//再加4個任務,核心執行緒滿了,應該5個熱核心執行緒,佇列5個,非核心執行緒5個,最後一個拒絕
for (int i = 0; i < 4; i++) {
try {
threadPoolExecutor.submit(new MyRunnable());
} catch (Exception e) {
e.printStackTrace(); //java.util.concurrent.RejectedExecutionException
}
}
System.out.println("worker count = " + threadPoolExecutor.getPoolSize()); //worker count = 10
System.out.println("queue size = " + threadPoolExecutor.getQueue().size()); //queue size = 5
System.out.println(threadPoolExecutor.getTaskCount()); //共執行15個任務
//執行完成,休眠15秒,非核心執行緒釋放,應該5個核心執行緒,佇列為0
Thread.sleep(1500);
System.out.println("worker count = " + threadPoolExecutor.getPoolSize()); //worker count = 5
System.out.println("queue size = " + threadPoolExecutor.getQueue().size()); //queue size = 0
//關閉執行緒池
threadPoolExecutor.shutdown();
}
作者:京東零售 秦浩然
來源:京東雲開發者社群 轉載請註明來源