" />

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

Java線程池復(fù)用線程的秘密你知道嗎

 更新時間:2022年03月07日 10:58:09   作者:Maybe_9527  
這篇文章主要為大家詳細(xì)介紹了Java線程池復(fù)用線程的秘密,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望您能夠多多關(guān)注

前言

我們都知道線程池可以幫我們管理線程,重復(fù)利用線程執(zhí)行不同的任務(wù)。正常情況下,我們創(chuàng)建的線程執(zhí)行完任務(wù)后就會自行銷毀,那么線程池是如何做到復(fù)用線程的呢?

源碼探究

我們從線程池ThreadPoolExecutor源碼入手,一探究竟。為了突出重點(diǎn),以下的方法源碼過濾了部分無關(guān)代碼,以求邏輯清晰。

execute方法

那就從線程池執(zhí)行的execute方法入手吧!來看一下方法的源碼

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();        
        int c = ctl.get();
        //1.小于核心線程數(shù)時,創(chuàng)建線程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        //2.達(dá)到核心線程數(shù),不超過隊(duì)列界限時,添加到隊(duì)列
        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);
        }
        //3.隊(duì)列已滿,不超過最大線程數(shù)時,創(chuàng)建線程
        else if (!addWorker(command, false))
        //4.達(dá)到最大線程數(shù)時,執(zhí)行拒絕策略
            reject(command);
    }

線程池執(zhí)行的4個步驟相信大家已經(jīng)有所了解,這里我們只看添加線程的方法addWorker()

addWorker方法

private boolean addWorker(Runnable firstTask, boolean core) {
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
        	//1.創(chuàng)建Worker,傳入任務(wù)
            w = new Worker(firstTask);
            //2.取出執(zhí)行任務(wù)的線程
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {                    
                    int c = ctl.get();
                    if (isRunning(c) ||
                        (runStateLessThan(c, STOP) && firstTask == null)) {
                        if (t.getState() != Thread.State.NEW)
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        workerAdded = true;
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                	//3.執(zhí)行線程
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

參數(shù)解釋:

core:true表示添加的是核心線程,false表示添加的非核心線程

這里大家只需要關(guān)心這3行加注釋的代碼就可以了

就是Worker管理了創(chuàng)建的線程和這個線程執(zhí)行的第一個任務(wù),并且在addWorker方法中調(diào)用線程的start方法,開啟線程執(zhí)行了任務(wù)。下面我們看看Worker這個類

Worker類

實(shí)現(xiàn)了Runnable接口

Worker 是線程池ThreadPoolExecutor的內(nèi)部類,實(shí)現(xiàn)了Runnable接口

private final class Worker    extends AbstractQueuedSynchronizer    implements Runnable

重要屬性

他有兩個核心關(guān)鍵的屬性,即封裝了線程池的線程和要執(zhí)行的任務(wù),達(dá)到了線程和任務(wù)解耦的目的。

final Thread thread;
Runnable firstTask;

構(gòu)造方法

addWorker方法會執(zhí)行創(chuàng)建一個worker

w = new Worker(firstTask);

看一下Worker的構(gòu)造方法

Worker(Runnable firstTask) {
	this.firstTask = firstTask;    		
	this.thread = getThreadFactory().newThread(this);
}

可以看到 新創(chuàng)建的Worker本身也是一個Runnable,他的thread傳的runnable任務(wù)就是worker本身

在addWorker方法,最終會取到worker的thread屬性,然后啟動這個thread

w = new Worker(firstTask);
final Thread t = w.thread;
... ...
t.start();

run方法

剛才介紹過,worker的thread的runnable參數(shù)傳的就是worker本身,就是調(diào)的worker的run方法,現(xiàn)在我們來看最核心的worker的run方法

public void run() { 
	runWorker(this);
}

調(diào)的是ThreadPoolExecutor的runWorker方法

final void runWorker(Worker w) {
    Runnable task = w.firstTask;
    w.firstTask = null;
    try { 
        while (task != null || (task = getTask()) != null) 
        {           
            ...           
            task.run();
            ...

可以看到runWorker核心是一個while循環(huán),執(zhí)行了第一個task之后,就不停的從隊(duì)列中取任務(wù),直到?jīng)]有任務(wù)了才會執(zhí)行完,銷毀線程

執(zhí)行流程

execute方法調(diào)用addWorker方法,并且執(zhí)行worker.thread.start()開啟線程

? ——》worker.thread 執(zhí)行worker本身的run方法(worker實(shí)現(xiàn)了Runnable接口)

? ——》執(zhí)行ThreadPoolExecutor的runWorker方法,是個while循環(huán),執(zhí)行完worker本身的第一個任務(wù)之后,就不停從隊(duì)列取任務(wù),直到?jīng)]有任務(wù),執(zhí)行完,退出循環(huán),銷毀

總結(jié)

線程池將線程和任務(wù)進(jìn)行解耦,線程是線程,任務(wù)是任務(wù),擺脫了之前通過 Thread 創(chuàng)建線程時的一個線程必須對應(yīng)一個任務(wù)的限制。

在線程池中,同一個線程可以從阻塞隊(duì)列中不斷獲取新任務(wù)來執(zhí)行,其核心原理在于線程池對 Thread 進(jìn)行了封裝,并不是每次執(zhí)行任務(wù)都會調(diào)用 Thread.start() 來創(chuàng)建新線程,而是讓每個線程去執(zhí)行一個“循環(huán)任務(wù)”,在這個“循環(huán)任務(wù)”中不停的檢查是否有任務(wù)需要被執(zhí)行,如果有則直接執(zhí)行,也就是調(diào)用任務(wù)中的 run 方法,將 run 方法當(dāng)成一個普通的方法執(zhí)行,通過這種方式將只使用固定的線程就將所有任務(wù)的 run 方法串聯(lián)起來。

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!             

相關(guān)文章

  • springboot如何使用yml文件方式配置shardingsphere

    springboot如何使用yml文件方式配置shardingsphere

    這篇文章主要介紹了springboot如何使用yml文件方式配置shardingsphere問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java輸入/輸出流體系詳解

    Java輸入/輸出流體系詳解

    這篇文章主要介紹了Java輸入/輸出流體系詳解,涉及字節(jié)流和字符流,輸入輸出體系,轉(zhuǎn)換流,以及文件的讀寫等相關(guān)內(nèi)容,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Java遍歷Json中的key和value問題

    Java遍歷Json中的key和value問題

    這篇文章主要介紹了Java遍歷Json中的key和value問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SpringBoot項(xiàng)目啟動數(shù)據(jù)加載內(nèi)存的三種方法

    SpringBoot項(xiàng)目啟動數(shù)據(jù)加載內(nèi)存的三種方法

    一般來說,SpringBoot工程環(huán)境配置放在properties文件中,啟動的時候?qū)⒐こ讨械膒roperties/yaml文件的配置項(xiàng)加載到內(nèi)存中,本文給大家介紹了SpringBoot項(xiàng)目啟動數(shù)據(jù)加載內(nèi)存中的三種方法,需要的朋友可以參考下
    2024-04-04
  • k8s部署MongDB全過程

    k8s部署MongDB全過程

    文章介紹了如何在Kubernetes集群中部署MongoDB,包括環(huán)境準(zhǔn)備、創(chuàng)建Secret、創(chuàng)建服務(wù)和Deployment,并通過Robo3T工具測試連接
    2025-01-01
  • Java?JDK的多版本共存實(shí)現(xiàn)方法

    Java?JDK的多版本共存實(shí)現(xiàn)方法

    有時候系統(tǒng)中需要多個jdk版本共存,我們在做特定的操作時需要特定的版本,這篇文章主要給大家介紹了關(guān)于Java?JDK的多版本共存實(shí)現(xiàn)?的相關(guān)資料,需要的朋友可以參考下
    2023-09-09
  • Java?Chassis3的多種序列化方式支持技術(shù)解密

    Java?Chassis3的多種序列化方式支持技術(shù)解密

    這篇文章主要為大家介紹了Java?Chassis?3多種序列化方式支持技術(shù)解密,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • SpringBoot集成RabbitMQ和概念介紹

    SpringBoot集成RabbitMQ和概念介紹

    這篇文章主要介紹了SpringBoot集成RabbitMQ和概念介紹,RabbitMQ即一個消息隊(duì)列,主要是用來實(shí)現(xiàn)應(yīng)用程序的異步和解耦,同時也能起到消息緩沖,消息分發(fā)的作用。更多相關(guān)內(nèi)容需要的小伙伴可以參考一下下面文章內(nèi)容
    2022-05-05
  • Java實(shí)現(xiàn)動物換位游戲完整?過程詳解

    Java實(shí)現(xiàn)動物換位游戲完整?過程詳解

    大家好,今天嘗試用Java編程設(shè)計(jì)一個GUI界面的動物換位游戲,游戲的結(jié)果是讓左右兩組的動物交換位置,以下是具體設(shè)計(jì)過程,供大家參考
    2022-07-07
  • Java基礎(chǔ)知識精通二維數(shù)組的應(yīng)用

    Java基礎(chǔ)知識精通二維數(shù)組的應(yīng)用

    為了方便組織各種信息,計(jì)算機(jī)常將信息以表的形式進(jìn)行組織,然后再以行和列的形式呈現(xiàn)出來。二維數(shù)組的結(jié)構(gòu)決定了其能非常方便地表示計(jì)算機(jī)中的表,以第一個下標(biāo)表示元素所在的行,第二個下標(biāo)表示元素所在的列。下面簡單了解一下二維數(shù)組,包括數(shù)組的聲明和初始化
    2022-04-04

最新評論

尤溪县| 双江| 汝阳县| 会理县| 石首市| 游戏| 登封市| 宁海县| 阿坝| 桓仁| 天峻县| 崇文区| 金门县| 华宁县| 临安市| 临沭县| 古蔺县| 甘孜| 瑞丽市| 巴林右旗| 巴南区| 东乌| 安顺市| 靖江市| 巴林左旗| 鄂温| 尉氏县| 探索| 茶陵县| 乐安县| 永康市| 万全县| 正阳县| 白玉县| 南投县| 永修县| 博野县| 昌邑市| 桃源县| 修水县| 封开县|