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

簡單剖析Java中動態(tài)線程池的擴容以及縮容操作

 更新時間:2025年01月24日 08:42:50   作者:程序員博博  
這篇文章主要為大家詳細介紹了Java中動態(tài)線程池的擴容以及縮容操作的相關(guān)知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

在項目中,我們經(jīng)常會使用到線程來處理加快我們的任務(wù)。但為了節(jié)約資源,大多數(shù)程序員都會把線程進行池化,使用線程池來更好的支持我們的業(yè)務(wù)。

Java線程池ThreadPoolExecutor有幾個比較核心的參數(shù),如corePoolSize、maximumPoolSize等等。無論是在工作中還是在面試中,都會被問到,如何正確的設(shè)置這幾個參數(shù)。

線程池的參數(shù)并不好配置。一方面線程池的運行機制不是很好理解,配置合理需要強依賴開發(fā)人員的個人經(jīng)驗和知識。項目IO密集型還是CPU密集型等等,總歸很難確定一個完美的參數(shù),此時就有了動態(tài)線程池的誕生。

動態(tài)線程池(DTP)原理

其實動態(tài)線程池并不是很高大上的技術(shù),它底層依舊是依賴了ThreadPoolExecutor的一些核心接口方法。我們通過下面圖片可以很清楚的看到,ThreadPoolExecutor本身就給我們提供了很多鉤子方法,讓我們?nèi)ザㄖ苹?/p>

那么其原理也非常簡單了,我們在運行中假設(shè)有一個線程池叫做TaskExecutor

  • 他的核心線程池默認假設(shè)是10,現(xiàn)在我發(fā)覺不夠用了,此時我想把他的核心線程池調(diào)整為20
  • 我可以寫一個遠程配置(可以阿波羅,zk,redis什么都可以)。然后監(jiān)聽到了這個配置變?yōu)榱薱ore.pool.size=20
  • 然后我獲取到了這個線程池TaskExecutor,并且調(diào)用setCorePoolSize(20),那么這個TaskExecutor核心線程數(shù)就變?yōu)榱?0

就是這么簡單,撥開表面,探究原理,內(nèi)部其實非常的簡單。當時公司里面的線程池還有加一些友好的界面、監(jiān)控告警、操作日志、權(quán)限校驗、審核等等,但本質(zhì)就是監(jiān)聽配置,然后調(diào)用setCorePoolSize方法去實現(xiàn)的,最大線程數(shù)類似。

public void setCorePoolSize(int corePoolSize) {
    if (corePoolSize < 0)
        throw new IllegalArgumentException();
    int delta = corePoolSize - this.corePoolSize;
    this.corePoolSize = corePoolSize;
    if (workerCountOf(ctl.get()) > corePoolSize)
        interruptIdleWorkers();
    else if (delta > 0) {
        int k = Math.min(delta, workQueue.size());
        while (k-- > 0 && addWorker(null, true)) {
            if (workQueue.isEmpty())
                break;
        }
    }
}

動態(tài)線程池縮容

首先提出幾個問題

  • 核心線程數(shù)為5,現(xiàn)在有3個線程在執(zhí)行,并且沒有執(zhí)行完畢,我修改核心線程數(shù)為4,是否修改成功
  • 核心線程數(shù)為5,現(xiàn)在有3個線程在執(zhí)行,并且沒有執(zhí)行完畢,我修改核心線程數(shù)為1,是否修改成功

讓我們帶著疑問去思考問題。

  • 首先第一個問題,因為核心線程池數(shù)為5,僅有3個在執(zhí)行,我修改為4,那么因為有2個空閑的線程,它只需要銷毀1個空閑線程即可,因此是成功的
  • 第二個問題,核心線程池數(shù)為5,僅有3個在執(zhí)行,我修改為1。雖然有2個空閑線程,但是我需要銷毀4個線程。因為有2個空閑線程,2個非空閑線程。我只能銷毀2個空閑線程,另外2個執(zhí)行的任務(wù)不能被打斷,也就是執(zhí)行后仍然為3個核心線程數(shù)。
  • 那什么時候銷毀剩下2個執(zhí)行的線程呢,等到2個執(zhí)行的任務(wù)完畢之后,就會銷毀它了。假設(shè)這個任務(wù)是一個死循環(huán),永遠不會結(jié)束,那么核心線程數(shù)永遠是3,永遠不能設(shè)置為1

我們舉一個代碼的例子如下

ThreadPoolExecutor es = new ThreadPoolExecutor(5, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
es.prestartAllCoreThreads();  // 預(yù)啟動所有核心線程

// 啟動三個任務(wù),執(zhí)行次數(shù)不一樣
for (int i = 0; i < 3; i++) {
    int finalI = i;
    es.execute(() -> {
        int cnt = 0;
        while (true) {
            try {
                cnt++;
                TimeUnit.SECONDS.sleep(2);

                if (cnt > finalI + 1) {
                    log.info(Thread.currentThread().getName() + " 執(zhí)行完畢");
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}
TimeUnit.SECONDS.sleep(1);  // 等待線程池中的線程執(zhí)行
log.info("修改前 es = {}", es);  // 這里核心線程數(shù)必定是5

es.setCorePoolSize(1);  // 修改核心線程數(shù)為1,但是核心線程數(shù)為5,并且有3個線程在執(zhí)行任務(wù),

while (true) {
    TimeUnit.SECONDS.sleep(1); // 等待
    log.info("修改后 es = {}", es);
}

輸出結(jié)果為如下

// 修改前核心線程數(shù)為5,運行線程數(shù)為3
[修改前 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 0]]

// 因為有2個空閑線程,先把2個空閑線程給銷毀了,剩下3個線程
[修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]]

// 等第1個任務(wù)執(zhí)行完畢,剩下2個線程
[Main.lambda$d$0:38] [pool-2-thread-1 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 1]]

// 等第2個任務(wù)執(zhí)行完畢,剩下1個線程
[Main.lambda$d$0:38] [pool-2-thread-2 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 2]]

// 等第3個任務(wù)執(zhí)行完畢,剩下1個線程。因為我修改的就是1個核心線程
[Main.lambda$d$0:38] [pool-2-thread-3 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@72d818d1[Running, pool size = 1, active threads = 0, queued tasks = 0, completed tasks = 3]]

有興趣的讀者可以拿這塊帶去自己去試試,輸出結(jié)果里面的注釋 我寫的非常詳細,大家可以詳細品品這塊輸出結(jié)果。

動態(tài)線程池擴容

擴容我就不提問問題了,和縮容異曲同工,但我希望讀者可以先看下以下代碼,不要看答案,認為會輸出什么結(jié)果,看下是否和自己想的是否一樣,如果一樣,那說明你已經(jīng)完全懂了,如果不一樣,是什么原因。

// 核心線程數(shù)1,最大線程數(shù)10
ThreadPoolExecutor es = new ThreadPoolExecutor(1, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
es.prestartAllCoreThreads();  // 預(yù)啟動所有核心線程

for (int i = 0; i < 5; i++) {
    int finalI = i;
    es.execute(() -> {
        int cnt = 0;
        while (true) {
            try {
                cnt++;
                TimeUnit.SECONDS.sleep(2);

                if (cnt > finalI + 1) {
                    log.info(Thread.currentThread().getName() + " 執(zhí)行完畢");
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
}

TimeUnit.SECONDS.sleep(1);  // 等待線程池中的線程執(zhí)行
log.info("修改前 es = {}", es);  // 這里核心線程數(shù)必定是1, 隊列里面有4個任務(wù)

es.setCorePoolSize(3);  // 修改核心線程數(shù)為3

while (true) {
    TimeUnit.SECONDS.sleep(1); // 等待
    log.info("修改后 es = {}", es);
}   

輸出結(jié)果為如下 (注意觀察輸出queued tasks的變化?。?!

[修改前 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 1, active threads = 1, queued tasks = 4, completed tasks = 0]]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 0]]

[Main.lambda$a$1:73] [pool-2-thread-1 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 3, queued tasks = 1, completed tasks = 1]]

[Main.lambda$a$1:73] [pool-2-thread-2 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 2]]

[Main.lambda$a$1:73] [pool-2-thread-3 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 3]]

[Main.lambda$a$1:73] [pool-2-thread-1 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 1, queued tasks = 0, completed tasks = 4]]

[Main.lambda$a$1:73] [pool-2-thread-2 執(zhí)行完畢]
[修改后 es = java.util.concurrent.ThreadPoolExecutor@1e397ed7[Running, pool size = 3, active threads = 0, queued tasks = 0, completed tasks = 5]]

最后

在業(yè)務(wù)中,我們?yōu)榱颂岣咝适褂昧司€程,為了加快線程我們使用了線程池,而又為了更好的利用線程池的資源,我們又實現(xiàn)了動態(tài)化線程池。這也就是遇到問題、探索問題、解決問題的一套思路吧。

我們從底層原理分析,發(fā)現(xiàn)動態(tài)線程池的底層原理非常簡單,希望大家不要恐懼,往往撥開外衣,發(fā)現(xiàn)里面最根本的原理,才能是我們更好的捋清楚其中的邏輯。

到此這篇關(guān)于簡單剖析Java中動態(tài)線程池的擴容以及縮容操作的文章就介紹到這了,更多相關(guān)Java動態(tài)線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)SM3withSM2簽名和驗證的基本示例

    Java實現(xiàn)SM3withSM2簽名和驗證的基本示例

    這篇文章主要介紹了Java實現(xiàn)SM3withSM2簽名和驗證的基本示例,SM3withSM2是一種在Java中使用的密碼學(xué)算法組合,結(jié)合了橢圓曲線公鑰密碼算法SM2和密碼哈希算法SM3,它主要用于數(shù)字簽名和數(shù)據(jù)完整性校驗,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-04-04
  • Java使用screw來對比數(shù)據(jù)庫表和字段差異

    Java使用screw來對比數(shù)據(jù)庫表和字段差異

    這篇文章主要介紹了Java如何使用screw來對比數(shù)據(jù)庫表和字段差異,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-12-12
  • Spring事務(wù)的七種傳播行為

    Spring事務(wù)的七種傳播行為

    這篇文章主要介紹了Spring事務(wù)的七種傳播行為,文章圍繞主題的相關(guān)資料展開詳細的內(nèi)容解說,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-04-04
  • Java Socket聊天室編程(一)之利用socket實現(xiàn)聊天之消息推送

    Java Socket聊天室編程(一)之利用socket實現(xiàn)聊天之消息推送

    這篇文章主要介紹了Java Socket聊天室編程(一)之利用socket實現(xiàn)聊天之消息推送的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • 詳解Spring Batch 輕量級批處理框架實踐

    詳解Spring Batch 輕量級批處理框架實踐

    這篇文章主要介紹了詳解Spring Batch 輕量級批處理框架實踐,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • Java設(shè)計模式中的適配器模式

    Java設(shè)計模式中的適配器模式

    這篇文章主要介紹了Java設(shè)計模式中的適配器模式, 適配器模式是將一個類的接口適配成用戶所期待的,一個適配允許通常因為接口不兼容而不能在一起工作的類工作在一起,做法是將類自己的接口包裹在一個已存在的類中,需要的朋友可以參考下
    2024-01-01
  • Java下界通配符(? super Type)的使用

    Java下界通配符(? super Type)的使用

    在Java中,? super Type是一個下界通配符,本文主要介紹了Java下界通配符(? super Type)的使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • JDBC中PreparedStatement詳解以及應(yīng)用場景實例介紹

    JDBC中PreparedStatement詳解以及應(yīng)用場景實例介紹

    PreparedStatement對象代表的是一個預(yù)編譯的SQL語句,用它提供的setter方法可以傳入查詢的變量,這篇文章主要給大家介紹了關(guān)于JDBC中PreparedStatement詳解以及應(yīng)用場景實例介紹的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • java批量修改文件后綴名方法總結(jié)

    java批量修改文件后綴名方法總結(jié)

    在本篇文章里小編給大家分享了關(guān)于java批量修改文件后綴名方法和相關(guān)知識點,有需要的朋友們學(xué)習(xí)下。
    2019-03-03
  • SpringCloud使用feign調(diào)用錯誤的問題

    SpringCloud使用feign調(diào)用錯誤的問題

    這篇文章主要介紹了SpringCloud使用feign調(diào)用錯誤的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評論

镇平县| 怀柔区| 长葛市| 永新县| 鹤庆县| 深州市| 随州市| 嘉禾县| 嘉峪关市| 资源县| 关岭| 河北区| 泽普县| 镇康县| 孟津县| 泰安市| 石河子市| 六枝特区| 株洲市| 海城市| 广东省| 忻城县| 宁陕县| 荣成市| 容城县| 上高县| 永善县| 综艺| 高安市| 麟游县| 库伦旗| 西平县| 福贡县| 万盛区| 资阳市| 麦盖提县| 漳州市| 永兴县| 内江市| 金堂县| 万山特区|