偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

線程池中線程是如何?;詈突厥盏?/h1>

開(kāi)發(fā)
面試時(shí)經(jīng)常被問(wèn)的一個(gè)問(wèn)題,線程池中線程是如何?;畹模楷F(xiàn)在我們就一起看一下線程池線程的?;畈呗?。

面試時(shí)經(jīng)常被問(wèn)的一個(gè)問(wèn)題,線程池中線程是如何?;畹??

這個(gè)問(wèn)題對(duì)于看過(guò)線程池源碼的同學(xué)應(yīng)該已經(jīng)知道答案了,沒(méi)有看過(guò)源碼的也不要慌,現(xiàn)在我們就一起看一下線程池線程的保活策略。

一、線程池中在哪執(zhí)行任務(wù)

首先進(jìn)入ThreadPoolExecutor的execute方法。

  • 首先檢查當(dāng)前工作線程數(shù)量,workerCountOf(c) 是否小于核心線程數(shù)量corePoolSize,如果小于就創(chuàng)建一個(gè)新線程addWorker()執(zhí)行這個(gè)任務(wù)。
  • 如果線程池在運(yùn)行且任務(wù)加入隊(duì)列成功,但是當(dāng)前工作線程數(shù)量為0,也會(huì)創(chuàng)建一個(gè)新線程addWorker()。
  • 如果任務(wù)不能被加入任務(wù)隊(duì)列(workQueue.offer(command)返回false), 也會(huì)創(chuàng)建一個(gè)新線程addWorker()。

在execute方法內(nèi)部有三處調(diào)用addWorker()方法的位置,進(jìn)入到addWorker() 方法中,可以看到有這樣一行代碼new Worker(firstTask) 。

而 Worker類(lèi)又實(shí)現(xiàn)了 Runnable,所以線程池中的線程也就是Worker,而執(zhí)行就在run()方法內(nèi)部,我們只需要找到Worker類(lèi)中的run方法即可。

Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }

run 方法內(nèi)部調(diào)用了 runWorker,秘密就在runWorker方法內(nèi)部。

所以線程池中線程最終就在runWorker方法中執(zhí)行的。

二、getTask 獲取任務(wù)方法

在上面ThreadPoolExecutor的execute方法中,有一步是往阻塞隊(duì)列中放入任務(wù)(workQueue.offer(command))。

上面我們找到了線程池中線程執(zhí)行任務(wù)的地方,那么我們看看是從哪讀取的任務(wù)?

runWorker方法中有一行代碼task = getTask(),此處就是從阻塞隊(duì)列中獲取任務(wù)的代碼,讓我們看一下 getTask() 的內(nèi)部實(shí)現(xiàn)。

核心代碼就是

Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();

根據(jù)timed 的狀態(tài)判斷,當(dāng)工作線程數(shù)量大于核心線程數(shù)量時(shí)調(diào)用poll方法獲取任務(wù),當(dāng)工作線程數(shù)量小于和核心線程數(shù)量時(shí)調(diào)用take方法。

對(duì)于阻塞隊(duì)列的介紹如下:

  • poll 方法如果隊(duì)列不為空,返回頭部元素。如果隊(duì)列為空會(huì)將線程阻塞在此處,阻塞時(shí)間是keepAliveTime。當(dāng)時(shí)間到了獲取不到任務(wù)時(shí)返回null。
  • take方法如果隊(duì)列不為空返回頭部元素。如果隊(duì)列為空會(huì)將線程阻塞在此處,直到隊(duì)列中有元素可供使用。

對(duì)于非核心線程,當(dāng)線程池中的線程數(shù)量超過(guò)核心線程數(shù)量且空閑時(shí)間超過(guò)keepAliveTime時(shí),非核心線程會(huì)被回收。

通過(guò)這種方式,線程在沒(méi)有任務(wù)時(shí)就阻塞在隊(duì)列上,從而實(shí)現(xiàn)?;睢?/p>

上面我們知道了非核心線程的?;畈呗裕敲磳?duì)于核心線程又是如何保活的呢?

三、核心線程如何實(shí)現(xiàn)的?;?/h4>

在線程池中核心線程默認(rèn)是不會(huì)被回收的。

不過(guò)我們可以通過(guò)設(shè)置allowCoreThreadTimeOut來(lái)實(shí)現(xiàn),getTask方法中timed的校驗(yàn)。

boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

所以當(dāng)allowCoreThreadTimeOut 設(shè)置為true時(shí),核心線程在沒(méi)有任務(wù)可以執(zhí)行時(shí)會(huì)使用take方法進(jìn)行阻塞,直到獲取到任務(wù)位置,而不是因?yàn)闆](méi)有任務(wù)就被銷(xiāo)毀,從而實(shí)現(xiàn)的線程?;睢?/p>

任務(wù)執(zhí)行的過(guò)程是無(wú)法保證不出問(wèn)題的,不管是核心線程還是非核心線程,當(dāng)線程中出現(xiàn)異常之后,線程池是如何處理的呢?

四、線程異常之后如何?;?/h4>

繼續(xù)回到runWorker方法中,其中task.run()是真正執(zhí)行任務(wù)的地方,當(dāng)此處發(fā)生異常之后,有try catch。

所以當(dāng)任務(wù)執(zhí)行異常之后,會(huì)依次執(zhí)三個(gè)finally塊中的代碼。

再看processWorkerExit() 方法之前,我們先看一個(gè)參數(shù)completedAbruptly。

completedAbruptly 代表是否是異常退出的,默認(rèn)是true代表異常退出。

在runWorker方法中,如果線程任務(wù)是正常執(zhí)行完成的,會(huì)在最后修改該值。

由于我們是異常線程,所以代碼肯定不會(huì)走到這,直接走到finally中的processWorkerExit方法。

在processWorkerExit方法中,它會(huì)根據(jù)completedAbruptly的值來(lái)調(diào)整線程池中的工作線程數(shù)量,從工作線程集合中移除該線程,并根據(jù)線程池的狀態(tài)和工作線程數(shù)量決定是否需要添加新線程。

!completedAbruptly 判斷工作線程是不是異常退出的,如果不是異常退出的計(jì)算最小線程數(shù)量。

如果允許核心線程回收allowCoreThreadTimeOut=true,min為0。

如果min為0 且工作隊(duì)列不為空! workQueue.isEmpty(),min為1。

如果當(dāng)前工作線程workerCountOf(c)大于等于這個(gè)最小的線程數(shù)量min,直接返回。

如果小于這個(gè)最小的工作線程數(shù)量min,調(diào)用addWorker。

此處addWorker 的觸發(fā)條件就是當(dāng)線程池的狀態(tài)小于STOP 也就是線程池還在運(yùn)行runStateLessThan(c, STOP)時(shí)且不滿足上述不需要添加新線程的判斷。

當(dāng)上述條件滿足的時(shí)候,則調(diào)用addWorker(null,false)添加一個(gè)新的工作線程,因?yàn)閭魅氲膮?shù)Runnable為null,所以這個(gè)新線程會(huì)從任務(wù)隊(duì)列中繼續(xù)讀取任務(wù)來(lái)執(zhí)行。

最后總結(jié)一下,當(dāng)線程異常之后,按照正常情況來(lái)說(shuō)線程就直接消失了,但是通過(guò)processWorkerExit方法的補(bǔ)救,增加了一個(gè)新的線程,保證線程池的運(yùn)行。

五、總結(jié)

線程池中的線程分為核心線程與非核心線程。

核心線程默認(rèn)不回收,可以通過(guò)設(shè)置allowCoreThreadTimeOut為true 來(lái)回收。

非核心線程在獲取任務(wù)為空且空閑時(shí)間超過(guò)一定時(shí)間之后進(jìn)行回收。

線程池的?;畈呗酝ㄟ^(guò)阻塞隊(duì)列的阻塞特性實(shí)現(xiàn),poll 方法實(shí)現(xiàn)可以指定超時(shí)時(shí)間的阻塞,take 方法實(shí)現(xiàn)阻塞直到獲取到任務(wù)。

當(dāng)線程異常之后,通過(guò)新增線程的方式實(shí)現(xiàn)線程的補(bǔ)救,保證線程池的運(yùn)行。

責(zé)任編輯:趙寧寧 來(lái)源: 醉魚(yú)Java
相關(guān)推薦

2024-06-13 09:30:33

Java線程池線程

2024-08-29 08:54:35

2023-02-02 08:56:25

線程池線程submit

2020-02-26 15:12:43

線程池增長(zhǎng)回收

2024-04-02 09:53:08

線程池線程堆棧

2025-02-05 14:28:19

2021-11-29 10:55:11

線程池Java面試

2011-06-01 11:23:09

Android 線程

2021-06-17 06:57:10

SpringBoot線程池設(shè)置

2019-09-26 10:19:27

設(shè)計(jì)電腦Java

2022-10-12 09:01:52

Linux內(nèi)核線程

2012-01-16 09:00:56

線程

2024-04-08 10:09:37

TTLJava框架

2023-10-26 08:25:35

Java線程周期

2021-06-24 08:02:35

線程池Java代碼

2024-08-30 08:23:06

2020-10-12 08:32:34

瀏覽器進(jìn)程線程

2024-05-20 13:13:01

線程安全Java

2022-10-24 08:03:04

MySQL數(shù)據(jù)庫(kù)

2022-09-06 08:25:13

線程異步任務(wù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)