溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何在Java中使用ThreadPoolExecutor

發(fā)布時間:2021-05-17 15:19:00 來源:億速云 閱讀:139 作者:Leah 欄目:開發(fā)技術(shù)

本篇文章給大家分享的是有關(guān)如何在Java中使用ThreadPoolExecutor,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

一、前言

線程池主要由以下4個核心組件組成。

  • 線程池管理器:用于創(chuàng)建并管理線程池

  • 工作線程:線程池中執(zhí)行具體任務(wù)的線程

  • 任務(wù)接口:用于定義工作線程的調(diào)度和執(zhí)行策略,只有線程實現(xiàn)了該接口,線程中的任務(wù)才能被線程池調(diào)度

  • 任務(wù)隊列:放待處理的任務(wù),新的任務(wù)將會不斷被加入隊列中,執(zhí)行完成的任務(wù)將從隊列中移除

如何在Java中使用ThreadPoolExecutor

二、ThreadPoolExecutor

如下是線程池的構(gòu)造方法

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
}

其中具體參數(shù)含義為:

1.corePoolSize:線程池中核心線程的數(shù)量

2.maximumPoolSize:線程池中最大線程的數(shù)量

3.keepAliveTime:當(dāng)線程數(shù)量超過corePoolSize時,空閑線程的存活時間

4.unit:keepAliveTime的時間單位

5.workQueue:任務(wù)隊列,被提交但尚未被執(zhí)行的任務(wù)存放的地方

6.threadFactory:線程工廠,用于創(chuàng)建線程,可使用默認的線程工廠或自定義線程工廠

7.handler:由于任務(wù)過多或其他原因?qū)е戮€程池?zé)o法處理時的任務(wù)拒絕策略

三、構(gòu)造函數(shù)參數(shù)解析

編寫測試類如下:

public class ThreadPoolSerialTest {
    public static void main(String[] args) {
        //核心線程數(shù)
        int corePoolSize = 2;
        //最大線程數(shù)
        int maximumPoolSize = 4;
        //超過corePoolSize線程數(shù)量的線程最大空閑時間
        long keepAliveTime = 2;
        //以秒為時間單位
        TimeUnit unit = TimeUnit.SECONDS;
        //創(chuàng)建工作隊列,用于存放提交的等待執(zhí)行任務(wù)
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadPoolExecutor threadPoolExecutor = null;

        try {
            // 1.創(chuàng)建線程池
            threadPoolExecutor = new ThreadPoolExecutor(corePoolSize,
                    maximumPoolSize,
                    keepAliveTime,
                    unit,
                    workQueue,
                    new ThreadPoolExecutor.AbortPolicy());
            // 2.循環(huán)提交任務(wù)
            for (int i = 0; i < 6; i++) {
                //提交任務(wù)的索引
                final int index = (i+1);
                threadPoolExecutor.submit(()->{
                    //線程打印輸出
                    System.out.println("大家好,我是線程:"+index);
                    try {
                        //模擬線程執(zhí)行時間,10s
                        Thread.sleep(10000);
                        System.out.println("線程:"+index+"運行完畢");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
                //每個任務(wù)提交后休眠500ms再提交下一個任務(wù),用于保證提交順序
                Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 3.關(guān)閉線程池
            threadPoolExecutor.shutdown();
        }
    }
}

其中循環(huán)了6次,讓線程池執(zhí)行了6次任務(wù),恰好滿足maximumPoolSize+workQueue容量=并發(fā)執(zhí)行任務(wù)數(shù)。輸出結(jié)果如下:

大家好,我是線程:1
大家好,我是線程:2
大家好,我是線程:5
大家好,我是線程:6
線程:1運行完畢
大家好,我是線程:3
線程:2運行完畢
大家好,我是線程:4
線程:5運行完畢
線程:6運行完畢
線程:3運行完畢
線程:4運行完畢

這段輸出看似沒有規(guī)律,其實這里輸出完全是由線程池控制的;下面就來分行解析輸出:

大家好,我是線程:1
大家好,我是線程:2
大家好,我是線程:5
大家好,我是線程:6

1.全新線程池被創(chuàng)建后,有Runnable或CallBack接口的實現(xiàn)被提交給線程池執(zhí)行;線程池的corePoolSize=2,此時前兩個任務(wù)提交后就立即執(zhí)行,便輸出了線程1 線程2;

2.此時仍繼續(xù)向線程池提交任務(wù),線程池中workQueue容量=2,被加入的任務(wù)存放到任務(wù)隊列中,即把線程3 線程4存放到了任務(wù)隊列中;

3.任務(wù)隊列充滿后,仍繼續(xù)向線程池提交任務(wù),線程池的maximumPoolSize=4,除開核心線程數(shù)2個外還允許創(chuàng)建4-2個線程來執(zhí)行任務(wù),便輸出了線程5 線程6

線程:1運行完畢
大家好,我是線程:3
線程:2運行完畢
大家好,我是線程:4

1.線程:1運行完畢:表示第一個線程任務(wù)執(zhí)行完畢了

2.大家好,我是線程:3:線程1運行完畢后,此時線程池中有一個空閑的線程,第一個進入任務(wù)隊列中的任務(wù)第一個交給線程處理

3.線程:2運行完畢 大家好,我是線程:4 :和上面線程執(zhí)行完畢,任務(wù)對列中任務(wù)執(zhí)行一致

線程:5運行完畢
線程:6運行完畢
線程:3運行完畢
線程:4運行完畢

因為每一個任務(wù)的執(zhí)行時間控制的是一樣的,此時輸出的內(nèi)容便是先被線程池執(zhí)行的任務(wù)先執(zhí)行完畢。

四、總結(jié)

線程池剛被創(chuàng)建時,只是向系統(tǒng)申請一個用于執(zhí)行線程隊列和管理線程池的資源。在調(diào)用execute()添加一個任務(wù)時,線程池會按照以下流程執(zhí)行任務(wù):

正在運行的線程數(shù)量a:a<corePoolSize,線程池立即創(chuàng)建線程并執(zhí)行任務(wù);若此時a=corePoolSize,則任務(wù)被存放到workQueue任務(wù)隊列中,直到任務(wù)隊列被充滿

任務(wù)隊列workQueue已充滿且正在運行的線程數(shù)a:a<maximumPoolSize,線程池立即創(chuàng)建非核心線程并執(zhí)行任務(wù);若有任務(wù)執(zhí)行完畢,該任務(wù)將被線程池隊列中移除,線程池從隊列中取先入隊的任務(wù)執(zhí)行;當(dāng)線程處于空閑狀態(tài)的時間超過keepAliveTime時間時,正在運行的線程數(shù)acorePoolSize<a,線程池停止空閑的線程。線程池將任務(wù)執(zhí)行完畢后,線程池會收縮到corePoolSize大小

任務(wù)隊列workQueue已充滿且正在運行的線程數(shù)a:a=maximumPoolSize,線程池拒絕執(zhí)行該任務(wù)并拋出RejectExecutionException異常

如何在Java中使用ThreadPoolExecutor

Java的優(yōu)點是什么

1. 簡單,只需理解基本的概念,就可以編寫適合于各種情況的應(yīng)用程序;2. 面向?qū)ο螅?. 分布性,Java是面向網(wǎng)絡(luò)的語言;4. 魯棒性,java提供自動垃圾收集來進行內(nèi)存管理,防止程序員在管理內(nèi)存時容易產(chǎn)生的錯誤。;5. 安全性,用于網(wǎng)絡(luò)、分布環(huán)境下的Java必須防止病毒的入侵。6. 體系結(jié)構(gòu)中立,只要安裝了Java運行時系統(tǒng),就可在任意處理器上運行。7. 可移植性,Java可以方便地移植到網(wǎng)絡(luò)上的不同機器。8.解釋執(zhí)行,Java解釋器直接對Java字節(jié)碼進行解釋執(zhí)行。

以上就是如何在Java中使用ThreadPoolExecutor,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI