執行緒池原理 JDK1 8原始碼解析

2021-08-21 13:25:02 字數 4203 閱讀 7748

執行緒池建立的方式:

public threadpoolexecutor(int corepoolsize,

int maximumpoolsize,

long keepalivetime,

timeunit unit,

blockingqueueworkqueue,

rejectedexecutionhandler handler)

引數的介紹:

corepoolsize:執行緒池核心執行緒數

maximumpoolsize:執行緒池最大執行緒數

keepalivetime:非核心執行緒數,空閒多久會被**

unit:空閒時間的單位

workqueue:執行緒池等待佇列的大小

handler:執行緒池達到飽和的策略處理類

執行緒池原理:

先看下面一張流程圖:

1.當乙個任務過來時,先判斷當前執行緒池的核心執行緒數是否已經建立滿了

如果沒有滿,直接建立執行緒,進行任務處理;如果滿了,進入到第二步

注意:這裡即使當前建立過的執行緒有空閒的,依然會重新建立執行緒執行任務,而不是拿空閒執行緒來用。

2.判斷當前的執行緒池佇列是否滿了,沒有滿,任務加入到佇列中進行排隊;如果滿了,進入到第三步

3.判斷當前執行緒池行程數量是否達到了最大執行緒數,如果沒有達到,建立執行緒執行當前任務,如果達到了,進入第4步處理

4.按照配置的飽和處理策略,進行處理

jdk1.8原始碼解析:

先看threadpoolexecutor的內部狀態實現方式:

private final atomicinteger ctl = new atomicinteger(ctlof(running, 0));

private static final int count_bits = integer.size - 3;

private static final int capacity = (1 << count_bits) - 1;

// runstate is stored in the high-order bits

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;

private static final int terminated = 3 << count_bits;

// packing and unpacking ctl

private static int runstateof(int c)

private static int workercountof(int c)

private static int ctlof(int rs, int wc)

我們可以看到這裡有乙個atomicinteger型別的ctl 變數:int一共是32位,這裡採用的是低位29位表示執行緒池執行緒的個數,高3位表示當前執行緒池的狀態。

count_bits:我們看這個常量,它的值=32-3=29

running    = -1 << count_bits; 這裡表示高3位是111,該狀態的執行緒池會接收新任務,並處理阻塞佇列中的任務;

shutdown   =  0 << count_bits;這裡表示高3位是000,該狀態的執行緒池不會接收新任務,但會處理阻塞佇列中的任務;

stop       =  1 << count_bits;這裡表示高3位是001,該狀態的執行緒池不會接收新任務,也不會處理阻塞佇列中的任務,並且會中斷正在執行的任務;

tidying    =  2 << count_bits;這裡表示高3位是010,表示當前執行緒池所有任務都已經終止了;

terminated =  3 << count_bits;這裡表示高3位是011,表示erminated()方法已經執行完成 ;

執行流程解析:

1.threadpoolexecutor的execute方法

public void execute(runnable command) 

//這裡需要判斷當前執行緒池的狀態=running,並且把當前任務加入到任務佇列裡

if (isrunning(c) && workqueue.offer(command))

//佇列也滿了,這個時候會建立非核心執行緒去執行任務

//如果失敗,直接走飽和拒絕策略處理

else if (!addworker(command, false))

reject(command);

}

注意:這裡做了雙重檢查,是因為多執行緒環境下,執行緒池的狀態是隨時變化的,而獲取狀態跟下面操作是非原子性的,如果不做雙層check,可能會出現執行緒變成了非執行狀態,結果卻把任務放到了執行任務佇列裡,導致任務無法執行。且不會通知到呼叫端。

2.addwork()方法:主要是建立執行緒並執行任務

private boolean addworker(runnable firsttask, boolean core) 

}boolean workerstarted = false;

boolean workeradded = false;

worker w = null;

try

} finally

//任務加入到worker成功 執行當前執行緒

if (workeradded)

}} finally

return workerstarted;

}

注意:這裡在新增到set的時候,做了加鎖處理,這裡主要是需要準確判斷當前執行緒池的狀態,在此處執行的時候,不容許其他執行緒修改當前執行緒池的狀態,已達到正確性。

3.worker.runworker()方法,這個是執行任務的核心方法:

final void runworker(worker w)  catch (runtimeexception x)  catch (error x)  catch (throwable x)  finally 

} finally

}completedabruptly = false;

} finally

}

整體流程為:

1.獲取當前任務;

2.執行緒啟動之後,通過unlock方法釋放鎖,設定aqs的state為0,表示執行可中斷; 

3.執行傳入的任務,或者是直接從執行緒池的任務佇列裡面獲取任務執行;

4.給當前執行緒加鎖,保證不會被其他前程中斷(如果執行緒池直接中斷,這裡也會中斷);

5.檢查當前執行緒池的狀態,如果當前執行緒池是中斷狀態,這直接中斷當前執行緒;

6.執行beforeexecute方法

7.執行當前任務的run方法

8.執行afterexecute方法 

9.解鎖  容許被其他執行緒中斷

4.我們看一下從任務佇列裡面獲取任務的方法:gettask()

private runnable gettask() 

//檢視當前執行中狀態的執行緒個數

int wc = workercountof(c);

// are workers subject to culling?

//如果配置了容許執行緒會被** 或者 當前執行緒數大於核心執行緒數

boolean timed = allowcorethreadtimeout || wc > corepoolsize;

//如果當前執行緒數大於最大執行緒數 或者是達到了**的條件

//而且執行緒數量大於1 或者 任務佇列已經空了

if ((wc > maximumpoolsize || (timed && timedout))

&& (wc > 1 || workqueue.isempty()))

try catch (interruptedexception retry) }}

執行緒池原理(JDK1 8)

2018 08 06 16 30 37 食魚醬 閱讀數 318更多 threadpoolexecutor是執行緒池類。對於執行緒池,可以通俗的將它理解為 存放一定數量執行緒的乙個執行緒集合。執行緒池允許若個執行緒同時允許,允許同時執行的執行緒數量就是執行緒池的容量 當新增的到執行緒池中的執行緒超過它...

Vector原始碼解析 jdk1 8

概述 vector實現了list的介面,底層同樣是基於陣列實現的,可以儲存null。功能結構與arraylist的類似,不同的是執行緒安全的。建構函式protected object elementdata protected int capacityincrement public vector ...

HashSet原始碼解析 JDK1 8

在我們學過hashmap之後,再來看hashset就很easy了。因為hashset是基於hashmap是實現的。開啟hashset的原始碼,可以看到維護了乙個hashmap 一 成員變數 用來儲存 hashset 的元素private transient hashmap,object map 這個...