線程池的基本結(jié)構(gòu)

線程池的基本結(jié)構(gòu)

就以ThreadPoolExecutor為例。當(dāng)我們把一個(gè)Runnable交給線程池去執(zhí)行的時(shí)候,這個(gè)線程池處理的流程是這樣的:

  1. 先判斷線程池中的核心線程們是否空閑,如果空閑嘿架,就把這個(gè)新的任務(wù)指派給某一個(gè)空閑線程去執(zhí)行挪钓。如果沒有空閑河质,并且當(dāng)前線程池中的核心線程數(shù)還小于 corePoolSize押蚤,那就再創(chuàng)建一個(gè)核心線程。
  2. 如果線程池的線程數(shù)已經(jīng)達(dá)到核心線程數(shù)羹应,并且這些線程都繁忙揽碘,就把這個(gè)新來的任務(wù)放到等待隊(duì)列中去。如果等待隊(duì)列又滿了园匹,那么
  3. 查看一下當(dāng)前線程數(shù)是否到達(dá)maximumPoolSize雳刺,如果還未到達(dá),就繼續(xù)創(chuàng)建線程裸违。如果已經(jīng)到達(dá)了掖桦,就交給RejectedExecutionHandler來決定怎么處理這個(gè)任務(wù)。

看一下代碼:

public void execute(Runnable command){
if(command == null){
throw new NullPointerException
}
int c = ctl.get();
if(workerCountOf(c) < corePoolSize){
if(addWorker(command,true))
return;
c = ctl.get();
}
if(isRunning(c) && workQueue.offer(command)){
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command)){
reject(command);
}else if(workerCountOf(recheck) == 0){
addWorker(null,false);
}
}else if (! addWorker(command,false)){
reject(command);
}
}

工作線程和等待隊(duì)列

final void runWorker(Worker w) {
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 pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
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);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}

這段代碼里有幾個(gè)地方要注意的供汛,第一枪汪,我們可以使用beforeExecute和afterExecute這兩個(gè)方法去監(jiān)控任務(wù)的執(zhí)行情況,這些方法在ThreadPoolExecutor里都是空方法怔昨,我們可以重寫這些方法來實(shí)現(xiàn)線程池的監(jiān)控雀久。第二,就是線程的邏輯是不斷地執(zhí)行一個(gè)循環(huán)趁舀,去調(diào)用 getTask 方法來獲得任務(wù)

private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?

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))
return null;
continue;
}

try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}

RejectedExecutionHandler

當(dāng)隊(duì)列和線程池都滿了的時(shí)候赖捌,再有新的任務(wù)到達(dá),就必須要有一種辦法來處理新來的任務(wù)矮烹。Java線程池中提供了以下四種策略:

  1. AbortPolicy: 直接拋異常
  2. CallerRunsPolicy:讓調(diào)用者幫著跑這個(gè)任務(wù)
  3. DiscardOldestPolicy:丟棄隊(duì)列里最老的那個(gè)任務(wù)越庇,執(zhí)行當(dāng)前任務(wù)
  4. DiscardPolicy:不處理,直接扔掉
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末奉狈,一起剝皮案震驚了整個(gè)濱河市卤唉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仁期,老刑警劉巖搬味,帶你破解...
    沈念sama閱讀 211,290評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件境氢,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡碰纬,警方通過查閱死者的電腦和手機(jī)萍聊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悦析,“玉大人寿桨,你說我怎么就攤上這事∏看鳎” “怎么了亭螟?”我有些...
    開封第一講書人閱讀 156,872評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骑歹。 經(jīng)常有香客問我预烙,道長(zhǎng),這世上最難降的妖魔是什么道媚? 我笑而不...
    開封第一講書人閱讀 56,415評(píng)論 1 283
  • 正文 為了忘掉前任扁掸,我火速辦了婚禮,結(jié)果婚禮上最域,老公的妹妹穿的比我還像新娘谴分。我一直安慰自己,他們只是感情好镀脂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評(píng)論 6 385
  • 文/花漫 我一把揭開白布牺蹄。 她就那樣靜靜地躺著,像睡著了一般薄翅。 火紅的嫁衣襯著肌膚如雪沙兰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評(píng)論 1 290
  • 那天翘魄,我揣著相機(jī)與錄音僧凰,去河邊找鬼。 笑死熟丸,一個(gè)胖子當(dāng)著我的面吹牛训措,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播光羞,決...
    沈念sama閱讀 38,927評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼绩鸣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了纱兑?” 一聲冷哼從身側(cè)響起呀闻,我...
    開封第一講書人閱讀 37,691評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎潜慎,沒想到半個(gè)月后捡多,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蓖康,經(jīng)...
    沈念sama閱讀 44,137評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評(píng)論 2 326
  • 正文 我和宋清朗相戀三年垒手,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蒜焊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,622評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡科贬,死狀恐怖泳梆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情榜掌,我是刑警寧澤优妙,帶...
    沈念sama閱讀 34,289評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站憎账,受9級(jí)特大地震影響套硼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胞皱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評(píng)論 3 312
  • 文/蒙蒙 一邪意、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧朴恳,春花似錦、人聲如沸允蚣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嚷兔。三九已至森渐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冒晰,已是汗流浹背同衣。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留壶运,地道東北人耐齐。 一個(gè)月前我還...
    沈念sama閱讀 46,316評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蒋情,于是被迫代替她去往敵國(guó)和親埠况。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容