" />

亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java線程池復用線程的秘密你知道嗎

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

前言

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

源碼探究

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

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.達到核心線程數(shù),不超過隊列界限時,添加到隊列
        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.隊列已滿,不超過最大線程數(shù)時,創(chuàng)建線程
        else if (!addWorker(command, false))
        //4.達到最大線程數(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 = new Worker(firstTask);
            //2.取出執(zhí)行任務的線程
            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表示添加的非核心線程

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

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

Worker類

實現(xiàn)了Runnable接口

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

private final class Worker    extends AbstractQueuedSynchronizer    implements Runnable

重要屬性

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

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任務就是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之后,就不停的從隊列中取任務,直到?jīng)]有任務了才會執(zhí)行完,銷毀線程

執(zhí)行流程

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

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

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

總結(jié)

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

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

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

相關文章

  • Java內(nèi)部類和異常類的概念以及使用

    Java內(nèi)部類和異常類的概念以及使用

    這篇文章主要介紹了Java內(nèi)部類和異常類的概念以及使用,文中有非常詳細的代碼以及注釋,適合正在學習java基礎的同學們使用,需要的朋友可以參考下
    2021-04-04
  • 一個Java中BigDecimal的問題記錄

    一個Java中BigDecimal的問題記錄

    這篇文章主要給大家介紹了關于Java中一個BigDecimal問題的相關資料,通過文中介紹的方法可以很方便的解決BigDecimal進行計算的時候不管怎么計算,最后得到的值都沒有變化的問題,需要的朋友可以參考下
    2021-11-11
  • Java并發(fā)線程之線程池的知識總結(jié)

    Java并發(fā)線程之線程池的知識總結(jié)

    這篇文章主要介紹了Java并發(fā)線程之線程池的知識總結(jié),幫助大家更好的理解和學習Java并發(fā)線程的相關內(nèi)容,感興趣的朋友可以了解下
    2021-01-01
  • Ireport的安裝與使用教程

    Ireport的安裝與使用教程

    這篇文章主要介紹了Ireport的安裝與使用教程,需要的朋友可以參考下
    2021-10-10
  • springboot整合mqtt客戶端示例分享

    springboot整合mqtt客戶端示例分享

    這篇文章主要介紹了springboot整合mqtt客戶端示例分享的相關資料,需要的朋友可以參考下
    2023-07-07
  • Java8 日期、時間操作代碼

    Java8 日期、時間操作代碼

    在Java8之前,日期時間API一直被開發(fā)者詬病,包括:java.util.Date是可變類型,SimpleDateFormat非線程安全等問題。故此,Java8引入了一套全新的日期時間處理API,新的API基于ISO標準日歷系統(tǒng)
    2021-09-09
  • SVN報錯:Error Updating changes:svn:E155037的解決方案

    SVN報錯:Error Updating changes:svn:E155037的解決方案

    今天小編就為大家分享一篇關于SVN報錯:Error Updating changes:svn:E155037的解決方案,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • java環(huán)境變量path和classpath的配置

    java環(huán)境變量path和classpath的配置

    這篇文章主要為大家詳細介紹了java系統(tǒng)環(huán)境變量path和classpath的配置過程,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 簡單易懂的Java Map數(shù)據(jù)添加指南

    簡單易懂的Java Map數(shù)據(jù)添加指南

    Java提供了多種方法來往Map中添加數(shù)據(jù),開發(fā)者可以根據(jù)具體需求選擇合適的方法,需要的朋友可以參考下
    2023-11-11
  • springboot 實現(xiàn)bean手動注入操作

    springboot 實現(xiàn)bean手動注入操作

    這篇文章主要介紹了springboot 實現(xiàn)bean手動注入操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01

最新評論