JDK源碼分析 線程池

說(shuō)明

對(duì)于JDK源碼分析的文章扛点,僅僅記錄我認(rèn)為重要的地方。源碼的細(xì)節(jié)實(shí)在太多笨使,不可能面面俱到地寫(xiě)清每個(gè)邏輯。所以我的JDK源碼分析僚害,著重在JDK的體系架構(gòu)層面硫椰,具體源碼可以參考:http://www.cnblogs.com/skywang12345/category/455711.html

架構(gòu)圖

Executor 函數(shù)接口

Executor:提供一種將"任務(wù)提交"與"任務(wù)如何運(yùn)行"分離開(kāi)來(lái)的機(jī)制萨蚕。

void execute(Runnable command)

ExecutorService

ExecutorService提供了"將任務(wù)提交給執(zhí)行者的接口(submit方法)"靶草,"讓執(zhí)行者執(zhí)行任務(wù)(invokeAll, invokeAny方法)"的接口等等。

AbstractExecutorService

抽象類(lèi)岳遥,為ExecutorService中的函數(shù)接口提供了默認(rèn)實(shí)現(xiàn)奕翔。

ThreadPoolExecutor

大名鼎鼎的“線程池”。

ScheduledExecutorService

接口浩蓉,提供了“延時(shí)”和“周期執(zhí)行”接口派继。

ScheduledThreadPoolExecutor

繼承于ThreadPoolExecutor,并且實(shí)現(xiàn)了ScheduledExecutorService接口捻艳。它相當(dāng)于提供了"延時(shí)"和"周期執(zhí)行"功能的ScheduledExecutorService互艾。

Executors

靜態(tài)工廠類(lèi)。它通過(guò)靜態(tài)工廠方法返回 ExecutorService讯泣、ScheduledExecutorService纫普、ThreadFactory 和 Callable 等類(lèi)的對(duì)象。

示例

class MyThreadPool extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " is running... ");
    }
}

@Test
public void testThreadPoolExecutor() throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(2);
    for (int i = 0; i < 5; i++) {
        TimeUnit.SECONDS.sleep(2);
        pool.execute(new MyThreadPool());
    }
    pool.shutdown();
}

輸出:

pool-1-thread-1 is running... 
pool-1-thread-2 is running... 
pool-1-thread-1 is running... 
pool-1-thread-2 is running... 
pool-1-thread-1 is running... 

分析:

示例代碼中好渠,新建了一個(gè)大小固定為2的線程池昨稼,并將5個(gè)線程依次放入線程池。從輸出結(jié)果中可以看出拳锚,是線程pool-1-thread-1和線程pool-1-thread-2相互交替假栓,并沒(méi)有新建多余的線程。

靜態(tài)工廠類(lèi)

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

創(chuàng)建一個(gè)線程池霍掺,線程池的容量是nThreads匾荆。已提交但是沒(méi)有執(zhí)行的任務(wù),會(huì)被阻塞杆烁,直到有任務(wù)運(yùn)行完成牙丽。

newFixedThreadPool()在調(diào)用ThreadPoolExecutor()時(shí),會(huì)傳遞一個(gè)LinkedBlockingQueue()對(duì)象兔魂,而LinkedBlockingQueue單向鏈表實(shí)現(xiàn)的阻塞隊(duì)列烤芦。在線程池中,就是通過(guò)該阻塞隊(duì)列來(lái)實(shí)現(xiàn)"當(dāng)線程池中任務(wù)數(shù)量超過(guò)允許的任務(wù)數(shù)量時(shí)析校,部分任務(wù)會(huì)阻塞等待"构罗。

ThreadFactory

public static ThreadFactory defaultThreadFactory() {
    return new DefaultThreadFactory();
}
static class DefaultThreadFactory implements ThreadFactory {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;
    DefaultThreadFactory() {
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() :
                              Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                      poolNumber.getAndIncrement() +
                     "-thread-";
    }
    // 提供創(chuàng)建線程的API铜涉。
    public Thread newThread(Runnable r) {
        // 線程對(duì)應(yīng)的任務(wù)是Runnable對(duì)象r
        Thread t = new Thread(group, r,
                              namePrefix + threadNumber.getAndIncrement(),
                              0);
        // 設(shè)為“非守護(hù)線程”
        if (t.isDaemon())
            t.setDaemon(false);
        // 將優(yōu)先級(jí)設(shè)為“Thread.NORM_PRIORITY”
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}

excute 添加任務(wù)到“線程池”

public void execute(Runnable command) {
    // 如果任務(wù)為null,則拋出異常遂唧。
    if (command == null)
        throw new NullPointerException();
    // 獲取ctl對(duì)應(yīng)的int值芙代。該int值保存了"線程池中任務(wù)的數(shù)量"和"線程池狀態(tài)"信息
    int c = ctl.get();
    // 當(dāng)線程池中的任務(wù)數(shù)量 < "核心池大小"時(shí),即線程池中少于corePoolSize個(gè)任務(wù)盖彭。
    // 則通過(guò)addWorker(command, true)新建一個(gè)線程链蕊,并將任務(wù)(command)添加到該線程中;然后谬泌,啟動(dòng)該線程從而執(zhí)行任務(wù)滔韵。
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 當(dāng)線程池中的任務(wù)數(shù)量 >= "核心池大小"時(shí),
    // 而且掌实,"線程池處于允許狀態(tài)"時(shí)陪蜻,則嘗試將任務(wù)添加到阻塞隊(duì)列中。
    if (isRunning(c) && workQueue.offer(command)) {
        // 再次確認(rèn)“線程池狀態(tài)”贱鼻,若線程池異常終止了宴卖,則刪除任務(wù);然后通過(guò)reject()執(zhí)行相應(yīng)的拒絕策略的內(nèi)容邻悬。
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        // 否則症昏,如果"線程池中任務(wù)數(shù)量"為0,則通過(guò)addWorker(null, false)嘗試新建一個(gè)線程父丰,新建線程對(duì)應(yīng)的任務(wù)為null肝谭。
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 通過(guò)addWorker(command, false)新建一個(gè)線程,并將任務(wù)(command)添加到該線程中蛾扇;然后攘烛,啟動(dòng)該線程從而執(zhí)行任務(wù)。
    // 如果addWorker(command, false)執(zhí)行失敗镀首,則通過(guò)reject()執(zhí)行相應(yīng)的拒絕策略的內(nèi)容坟漱。
    else if (!addWorker(command, false))
        reject(command);
}

shutdown 關(guān)閉線程池

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    // 獲取鎖
    mainLock.lock();
    try {
        // 檢查終止線程池的“線程”是否有權(quán)限。
        checkShutdownAccess();
        // 設(shè)置線程池的狀態(tài)為關(guān)閉狀態(tài)更哄。
        advanceRunState(SHUTDOWN);
        // 中斷線程池中空閑的線程芋齿。
        interruptIdleWorkers();
        // 鉤子函數(shù),在ThreadPoolExecutor中沒(méi)有任何動(dòng)作成翩。
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        // 釋放鎖
        mainLock.unlock();
    }
    // 嘗試終止線程池
    tryTerminate();
}

線程池狀態(tài)

  • Running
  • SHUTDOWN
  • STOP
  • TIDYING
  • TERMINATED
rivate final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

ctl是一個(gè)AtomicInteger類(lèi)型的原子對(duì)象觅捆。ctl記錄了"線程池中的任務(wù)數(shù)量"和"線程池狀態(tài)"2個(gè)信息。
ctl共包括32位捕传。其中惠拭,高3位表示"線程池狀態(tài)",低29位表示"線程池中的任務(wù)數(shù)量"庸论。

RUNNING    -- 對(duì)應(yīng)的高3位值是111职辅。
SHUTDOWN   -- 對(duì)應(yīng)的高3位值是000。
STOP       -- 對(duì)應(yīng)的高3位值是001聂示。
TIDYING    -- 對(duì)應(yīng)的高3位值是010域携。
TERMINATED -- 對(duì)應(yīng)的高3位值是011。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鱼喉,一起剝皮案震驚了整個(gè)濱河市秀鞭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扛禽,老刑警劉巖锋边,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異编曼,居然都是意外死亡豆巨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)掐场,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)往扔,“玉大人,你說(shuō)我怎么就攤上這事熊户∑继牛” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵嚷堡,是天一觀的道長(zhǎng)蝗罗。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蝌戒,這世上最難降的妖魔是什么绿饵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮瓶颠,結(jié)果婚禮上拟赊,老公的妹妹穿的比我還像新娘。我一直安慰自己粹淋,他們只是感情好吸祟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著桃移,像睡著了一般屋匕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上借杰,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天过吻,我揣著相機(jī)與錄音,去河邊找鬼。 笑死纤虽,一個(gè)胖子當(dāng)著我的面吹牛乳绕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逼纸,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼洋措,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杰刽?” 一聲冷哼從身側(cè)響起菠发,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贺嫂,沒(méi)想到半個(gè)月后滓鸠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡第喳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年糜俗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墩弯。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吩跋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渔工,到底是詐尸還是另有隱情锌钮,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布引矩,位于F島的核電站梁丘,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏旺韭。R本人自食惡果不足惜氛谜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望区端。 院中可真熱鬧值漫,春花似錦、人聲如沸织盼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沥邻。三九已至危虱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唐全,已是汗流浹背埃跷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弥雹。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓垃帅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親缅糟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子挺智,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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