執行緒池建立的方式:
引數的介紹: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的內部狀態實現方式:
我們可以看到這裡有乙個atomicinteger型別的ctl 變數:int一共是32位,這裡採用的是低位29位表示執行緒池執行緒的個數,高3位表示當前執行緒池的狀態。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)
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方法
注意:這裡做了雙重檢查,是因為多執行緒環境下,執行緒池的狀態是隨時變化的,而獲取狀態跟下面操作是非原子性的,如果不做雙層check,可能會出現執行緒變成了非執行狀態,結果卻把任務放到了執行任務佇列裡,導致任務無法執行。且不會通知到呼叫端。public void execute(runnable command)
//這裡需要判斷當前執行緒池的狀態=running,並且把當前任務加入到任務佇列裡
if (isrunning(c) && workqueue.offer(command))
//佇列也滿了,這個時候會建立非核心執行緒去執行任務
//如果失敗,直接走飽和拒絕策略處理
else if (!addworker(command, false))
reject(command);
}
2.addwork()方法:主要是建立執行緒並執行任務
注意:這裡在新增到set的時候,做了加鎖處理,這裡主要是需要準確判斷當前執行緒池的狀態,在此處執行的時候,不容許其他執行緒修改當前執行緒池的狀態,已達到正確性。private boolean addworker(runnable firsttask, boolean core)
}boolean workerstarted = false;
boolean workeradded = false;
worker w = null;
try
} finally
//任務加入到worker成功 執行當前執行緒
if (workeradded)
}} finally
return workerstarted;
}
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 這個...