最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關(guān)于線程池創(chuàng)建、執(zhí)行、銷毀的原理及分析

 更新時(shí)間:2025年05月07日 14:06:26   作者:安益空間  
這篇文章主要介紹了關(guān)于線程池創(chuàng)建、執(zhí)行、銷毀的原理及分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

線程池的執(zhí)行原理

假設(shè)最大核心數(shù)是2,非核心線程數(shù)為1,隊(duì)列長(zhǎng)度是3

來(lái)第一個(gè)任務(wù)的時(shí)候,沒(méi)有工作線程在工作,需要?jiǎng)?chuàng)建一個(gè)

來(lái)第二個(gè)任務(wù)的時(shí)候,發(fā)現(xiàn)當(dāng)前核心線程數(shù)小于最大核心線程數(shù),所以繼續(xù)創(chuàng)建線程來(lái)處理任務(wù)

當(dāng)來(lái)第三個(gè)任務(wù)的時(shí)候,發(fā)現(xiàn)當(dāng)前核心線程數(shù)已經(jīng)等于最大核心線程數(shù)了,所以把新來(lái)的任務(wù)放到taskQueue中

后面來(lái)第四個(gè)、第五個(gè)任務(wù)也會(huì)放在taskQueue中

當(dāng)來(lái)第六個(gè)任務(wù)的時(shí)候,發(fā)現(xiàn)taskQueue已經(jīng)滿了,所以會(huì)創(chuàng)建一個(gè)非核心線程來(lái)處理任務(wù)

當(dāng)來(lái)第七個(gè)任務(wù)的時(shí)候,因?yàn)榫€程數(shù)量到最大限度了,taskQueue也滿了,所以就會(huì)走拒絕策略,把其中一個(gè)任務(wù)給拋棄掉,具體拋棄哪個(gè)需要根據(jù)選擇的拒絕策略來(lái)定。

創(chuàng)建線程這里需要考慮并發(fā)的問(wèn)題,即多個(gè)任務(wù)同時(shí)過(guò)來(lái)了,需要串行創(chuàng)建線程,否則,可能會(huì)導(dǎo)致超賣的情況(即創(chuàng)建的線程超過(guò)了最大線程數(shù)),具體是通過(guò)CAS樂(lè)觀鎖實(shí)現(xiàn),代碼解釋如下:

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            int c = ctl.get();//獲取當(dāng)前線程池的控制狀態(tài)。
            int rs = runStateOf(c);//獲取當(dāng)前線程池的運(yùn)行狀態(tài)。

            // Check if queue empty only if necessary.
            //下面這個(gè)條件判斷用于判斷線程池是否處于關(guān)閉狀態(tài),并且任務(wù)隊(duì)列不為空。如果線程池的狀態(tài)大于等于SHUTDOWN,并且不滿足線程池狀態(tài)為SHUTDOWN、首個(gè)任務(wù)為null且任務(wù)隊(duì)列為空的條件,則返回false。這個(gè)判斷是為了確保在線程池關(guān)閉時(shí),不再添加新的工作線程。
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);//獲取當(dāng)前線程池中的工作線程數(shù)量。
                //這個(gè)條件判斷用于判斷工作線程數(shù)量是否達(dá)到上限。如果工作線程數(shù)量大于等于CAPACITY(工作線程數(shù)量的上限)或者大于等于核心線程數(shù)(如果core為true)或最大線程數(shù)(如果core為false),則返回false。這個(gè)判斷是為了確保工作線程數(shù)量不超過(guò)線程池的限制。
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                    //嘗試通過(guò)CAS(比較并交換)操作增加工作線程數(shù)量。如果成功增加工作線程數(shù)量,則跳出循環(huán),繼續(xù)執(zhí)行后續(xù)邏輯。
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // 重新讀取當(dāng)前線程池的控制狀態(tài)。
                //再次判斷線程池的運(yùn)行狀態(tài)是否發(fā)生了變化。如果運(yùn)行狀態(tài)發(fā)生了變化,則繼續(xù)重試內(nèi)部循環(huán)。這個(gè)判斷是為了處理在CAS操作過(guò)程中,線程池的狀態(tài)發(fā)生了變化的情況。
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        ...創(chuàng)建線程的邏輯忽略...
}

線程執(zhí)行

花開(kāi)兩朵,各表一枝。

上面說(shuō)了任務(wù)來(lái)了之后,是怎么創(chuàng)建線程的,又是怎么暫存任務(wù)的。這一節(jié)介紹一下線程是怎么執(zhí)行任務(wù)的,以及在不用的時(shí)候,線程怎么被銷毀或者?;?。

線程池創(chuàng)建線程并調(diào)了thread的start方法之后,該線程會(huì)走到下面的runWorker方法。

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);
        }
    }

當(dāng)一個(gè)線程執(zhí)行完就會(huì)自動(dòng)退出,但是我們知道線程池中的核心線程會(huì)一直存活著,想要一直存活,不退出程序就可以了,即循環(huán),從上面的代碼也可以看出來(lái)確實(shí)是這樣的。但是還有一個(gè)疑問(wèn),核心線程是一直存活的,但是非核心線程在一定情況是會(huì)銷毀的,他們用的是一套代碼邏輯,該怎么實(shí)現(xiàn)呢?關(guān)鍵點(diǎn)就在getTask這個(gè)方法中。

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;
			//銷毀線程需要滿足這兩個(gè)條件:1. (允許核心線程銷毀 || 線程數(shù)大于核心線程數(shù))&& 達(dá)到了銷毀時(shí)間;2. 任務(wù)隊(duì)列中沒(méi)有任務(wù)了
            if ((wc > maximumPoolSize || (timed && timedOut)) 
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                // 這里返回了null,外層方法就跳出了while循環(huán),從而結(jié)束該線程
                    return null;
                continue;
            }

            try {
            // 超時(shí)時(shí)間就是在這里設(shè)置的,如果允許超時(shí)銷毀,那么就用poll進(jìn)行拉取任務(wù),超過(guò)了keepAliveTime就返回null。take是阻塞性等待
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

從上面的解析可以看出,如果隊(duì)列中沒(méi)有任務(wù)時(shí),小于核心數(shù)的線程(核心線程數(shù)不銷毀的情況下)會(huì)一直阻塞在獲取任務(wù)的方法,直到返回任務(wù)。(判斷阻塞時(shí)并沒(méi)有核心線程和非核心線程的概念,只要保證創(chuàng)建出來(lái)的線程銷毀到符合預(yù)期數(shù)量就ok)。而且執(zhí)行完后 會(huì)繼續(xù)循環(huán)執(zhí)行g(shù)etTask的邏輯,不斷的處理任務(wù)。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring Boot詳細(xì)打印啟動(dòng)時(shí)異常堆棧信息詳析

    Spring Boot詳細(xì)打印啟動(dòng)時(shí)異常堆棧信息詳析

    這篇文章主要給大家介紹了關(guān)于Spring Boot詳細(xì)打印啟動(dòng)時(shí)異常堆棧信息的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • Spring?MVC啟動(dòng)之HandlerMapping作用及實(shí)現(xiàn)詳解

    Spring?MVC啟動(dòng)之HandlerMapping作用及實(shí)現(xiàn)詳解

    這篇文章主要為大家介紹了Spring?MVC啟動(dòng)之HandlerMapping作用及實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Java Builder模式構(gòu)建MAP/LIST的實(shí)例講解

    Java Builder模式構(gòu)建MAP/LIST的實(shí)例講解

    下面小編就為大家?guī)?lái)一篇Java Builder模式構(gòu)建MAP/LIST的實(shí)例講解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Java中的Enum枚舉使用方法解析

    Java中的Enum枚舉使用方法解析

    這篇文章主要介紹了Java中的Enum枚舉使用方法解析,枚舉是一種數(shù)據(jù)類型,和int、double、string等類型相似,枚舉用于聲明一組命名的常數(shù),當(dāng)一個(gè)變量有幾種可能的取值時(shí),可以將它定義為枚舉類型,需要的朋友可以參考下
    2023-11-11
  • Java將文件夾保留目錄打包為 ZIP 壓縮包并下載的教程詳解

    Java將文件夾保留目錄打包為 ZIP 壓縮包并下載的教程詳解

    這篇文章主要介紹了Java將文件夾保留目錄打包為 ZIP 壓縮包并下載的教程詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 如何通過(guò)ServletInputStream讀取http請(qǐng)求傳入的數(shù)據(jù)

    如何通過(guò)ServletInputStream讀取http請(qǐng)求傳入的數(shù)據(jù)

    這篇文章主要介紹了如何通過(guò)ServletInputStream讀取http請(qǐng)求傳入的數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • java后臺(tái)調(diào)用HttpURLConnection類模擬瀏覽器請(qǐng)求實(shí)例(可用于接口調(diào)用)

    java后臺(tái)調(diào)用HttpURLConnection類模擬瀏覽器請(qǐng)求實(shí)例(可用于接口調(diào)用)

    這篇文章主要介紹了java后臺(tái)調(diào)用HttpURLConnection類模擬瀏覽器請(qǐng)求實(shí)例,該實(shí)例可用于接口調(diào)用,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下
    2014-10-10
  • Java實(shí)現(xiàn)按字節(jié)長(zhǎng)度截取字符串

    Java實(shí)現(xiàn)按字節(jié)長(zhǎng)度截取字符串

    在Java中,由于字符串可能包含多字節(jié)字符,直接按字節(jié)長(zhǎng)度截取可能會(huì)導(dǎo)致亂碼或截取不準(zhǔn)確的問(wèn)題,下面我們就來(lái)看看幾種按字節(jié)長(zhǎng)度截取字符串的方法吧
    2025-05-05
  • JAVA觀察者模式的的講解及代碼實(shí)現(xiàn)

    JAVA觀察者模式的的講解及代碼實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了JAVA的觀察者模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • 解決Java包裝類比較時(shí)遇到的問(wèn)題

    解決Java包裝類比較時(shí)遇到的問(wèn)題

    所謂包裝類的作用就是將原始數(shù)據(jù)類型轉(zhuǎn)換成引用數(shù)據(jù)類型,下面這篇文章主要給大家介紹了關(guān)于在Java包裝類比較時(shí)遇到的問(wèn)題的解決方法,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-09-09

最新評(píng)論

德令哈市| 兴山县| 江都市| 莱芜市| 青神县| 临夏县| 肇东市| 饶平县| 湖州市| 页游| 青海省| 东丰县| 漳州市| 彰化市| 招远市| 平谷区| 香港 | 五寨县| 麻栗坡县| 柏乡县| 平南县| 保康县| 胶南市| 抚顺县| 宁明县| 突泉县| 新营市| 三明市| 五常市| 青浦区| 泸定县| 乐平市| 金华市| 金秀| 涞源县| 河西区| 宁武县| 固阳县| 怀仁县| 濮阳县| 阿坝县|