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

Java中的線程池ThreadPoolExecutor深入解析

 更新時間:2023年11月09日 09:47:34   作者:莫輕言舞  
這篇文章主要介紹了Java中的線程池ThreadPoolExecutor深入解析,線程池,thread pool,是一種線程使用模式,線程池維護著多個線程,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務,需要的朋友可以參考下

1.什么是線程池?

線程池,thread pool,是一種線程使用模式,線程池維護著多個線程,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務。

通俗來說,就是可管理和維護以及分配線程的“池子”。

2.為什么使用線程池?

為了減少創(chuàng)建和銷毀線程的次數(shù),讓每個線程都可以多次的使用,可以根據(jù)系統(tǒng)情況調(diào)整線程的數(shù)量,防止消耗過多內(nèi)存。在實際使用中,服務器在創(chuàng)建和銷毀線程上花費的時間和消耗的系統(tǒng)資源都相當大,使用線程池就可以優(yōu)化。 線程池主要用來解決線程生命周期開銷問題和資源不足問題。通過對多個任務重復使用線程,線程創(chuàng)建的開銷就被分攤到了多個任務上了,而且由于在請求到達時線程已經(jīng)存在,所以消除了線程創(chuàng)建所帶來的延遲。這樣,就可以立即為請求服務,使用應用程序響應更快。另外,通過適當?shù)恼{(diào)整線程中的線程數(shù)目可以防止出現(xiàn)資源不足的情況。

通俗來說,就是為了優(yōu)化線程的內(nèi)存開銷。

3.線程池的核心參數(shù)

public ThreadPoolExecutor(int corePoolSize,//核心線程數(shù)
                          int maximumPoolSize,//最大線程數(shù)
                          long keepAliveTime,//線程空閑時間
                          TimeUnit unit,//時間單位
                          BlockingQueue<Runnable> workQueue,//任務隊列
                          ThreadFactory threadFactory,//線程工廠
                          RejectedExecutionHandler handler//拒絕策略) 
{
    ...
}

4.線程池的執(zhí)行順序

線程池按以下行為執(zhí)行任務

  • 當線程數(shù)小于核心線程數(shù)時,創(chuàng)建線程。
  • 當線程數(shù)大于等于核心線程數(shù),且任務隊列未滿時,將任務放入任務隊列。
  • 當線程數(shù)大于等于核心線程數(shù),且任務隊列已滿,若線程數(shù)小于最大線程數(shù),創(chuàng)建線程。
  • 若線程數(shù)等于最大線程數(shù),則執(zhí)行拒絕策略

5.線程池的參數(shù)詳解

(a)、corePoolSize

核心線程數(shù),默認為1。

設置規(guī)則:

CPU密集型(CPU密集型也叫計算密集型,指的是運算較多,cpu占用高,讀/寫I/O(硬盤/內(nèi)存)較少):corePoolSize = CPU核數(shù) + 1IO密集型(與cpu密集型相反,系統(tǒng)運作,大部分的狀況是CPU在等I/O (硬盤/內(nèi)存) 的讀/寫操作,此時CPU Loading并不高。):corePoolSize = CPU核數(shù) * 2

(b)、maximumPoolSize最大線程數(shù),默認為Integer.MAX_VALUE一般設置為和核心線程數(shù)一樣

(c)、keepAliveTime線程空閑時間,默認為60s,一般設置為默認60s

(d)、unit時間單位,默認為秒

(e)、workQueue隊列,當線程數(shù)目超過核心線程數(shù)時用于保存任務的隊列。(BlockingQueue workQueue)此隊列僅保存實現(xiàn)Runnable接口的任務。(因為線程池的底層BlockingQueue的泛型為Runnable)

(1)無界隊列

隊列大小無限制,常用的為無界的LinkedBlockingQueue,使用該隊列作為阻塞隊列時要尤其當心,當任務耗時較長時可能會導致大量新任務在隊列中堆積最終導致OOM。閱讀代碼發(fā)現(xiàn),Executors.newFixedThreadPool 采用就是 LinkedBlockingQueue,而博主踩到的就是這個坑,當QPS很高,發(fā)送數(shù)據(jù)很大,大量的任務被添加到這個無界LinkedBlockingQueue 中,導致cpu和內(nèi)存飆升服務器掛掉。

當然這種隊列,maximumPoolSize 的值也就無效了。當每個任務完全獨立于其他任務,即任務執(zhí)行互不影響時,適合于使用無界隊列;例如,在 Web 頁服務器中。這種排隊可用于處理瞬態(tài)突發(fā)請求,當命令以超過隊列所能處理的平均數(shù)連續(xù)到達時,此策略允許無界線程具有增長的可能性。

(2)有界隊列

當使用有限的 maximumPoolSizes 時,有界隊列有助于防止資源耗盡,但是可能較難調(diào)整和控制。常用的有兩類,一類是遵循FIFO原則的隊列如ArrayBlockingQueue,另一類是優(yōu)先級隊列如PriorityBlockingQueue。PriorityBlockingQueue中的優(yōu)先級由任務的Comparator決定。
使用有界隊列時隊列大小需和線程池大小互相配合,線程池較小有界隊列較大時可減少內(nèi)存消耗,降低cpu使用率和上下文切換,但是可能會限制系統(tǒng)吞吐量。

(3)同步移交隊列

如果不希望任務在隊列中等待而是希望將任務直接移交給工作線程,可使用SynchronousQueue作為等待隊列。SynchronousQueue不是一個真正的隊列,而是一種線程之間移交的機制。要將一個元素放入SynchronousQueue中,必須有另一個線程正在等待接收這個元素。只有在使用無界線程池或者有飽和策略時才建議使用該隊列。

(f)、threadFactory

線程工廠,用來創(chuàng)建線程。

為了統(tǒng)一在創(chuàng)建線程時設置一些參數(shù),如是否守護線程,線程一些特性等,如優(yōu)先級。通過這個TreadFactory創(chuàng)建出來的線程能保證有相同的特性。

它是一個接口類,而且方法只有一個,就是創(chuàng)建一個線程。

如果沒有另外說明,則在同一個ThreadGroup 中一律使用Executors.defaultThreadFactory() 創(chuàng)建線程,并且這些線程具有相同的NORM_PRIORITY 優(yōu)先級和非守護進程狀態(tài)。

通過提供不同的 ThreadFactory,可以改變線程的名稱、線程組、優(yōu)先級、守護進程狀態(tài),等等。

如果從newThread 返回 null 時ThreadFactory 未能創(chuàng)建線程,則執(zhí)行程序將繼續(xù)運行,但不能執(zhí)行任何任務。

(g)、handler

拒絕策略,默認是AbortPolicy,會拋出異常。

當線程數(shù)已經(jīng)達到maxPoolSize,且隊列已滿,會拒絕新任務。

當線程池被調(diào)用shutdown()后,會等待線程池里的任務執(zhí)行完畢再shutdown。如果在調(diào)用shutdown()和線程池真正shutdown之間提交任務,會拒絕新任務。

  • AbortPolicy 丟棄任務,拋運行時異常。
  • CallerRunsPolicy 由當前調(diào)用的任務線程執(zhí)行任務。
  • DiscardPolicy 忽視,什么都不會發(fā)生。
  • DiscardOldestPolicy 從隊列中踢出最先進入隊列(最后一個執(zhí)行)的任務。

6.ThreadPoolExecutor和spring封裝的ThreadPoolTaskExecutor案例

ThreadPoolExecutor是Java的線程池 ThreadPoolTaskExecutor是spring封裝的線程池

package com.thgy.bc.common.config;
 
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
import java.util.concurrent.*;
 
@Slf4j
@Configuration
public class ThreadPoolConfig {
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int i = Runtime.getRuntime().availableProcessors();
        //核心線程數(shù)目
        executor.setCorePoolSize(i * 2);
        //指定最大線程數(shù)
        executor.setMaxPoolSize(i * 2);
        //隊列中最大的數(shù)目
        executor.setQueueCapacity(i * 2 * 10);
        //線程名稱前綴
        executor.setThreadNamePrefix("ThreadPoolTaskExecutor-");
        //rejection-policy:當pool已經(jīng)達到max size的時候,如何處理新任務
        //CALLER_RUNS:不在新線程中執(zhí)行任務,而是由調(diào)用者所在的線程來執(zhí)行
        //對拒絕task的處理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //當調(diào)度器shutdown被調(diào)用時等待當前被調(diào)度的任務完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //線程空閑后的最大存活時間
        executor.setKeepAliveSeconds(60);
        //加載
        executor.initialize();
        log.info("初始化線程池成功");
        return executor;
    }
 
    @Bean
    public ThreadPoolExecutor threadPoolExecutor() {
        //獲取cpu核心數(shù)
        int i = Runtime.getRuntime().availableProcessors();
        //核心線程數(shù)
        int corePoolSize = i * 2;
        //最大線程數(shù)
        int maximumPoolSize = i * 2;
        //線程無引用存活時間
        long keepAliveTime = 60;
        //時間單位
        TimeUnit unit = TimeUnit.SECONDS;
        //任務隊列,接收一個整型的參數(shù),這個整型參數(shù)指的是隊列的長度,
        //ArrayBlockingQueue(int,boolean),boolean類型的參數(shù)是作為可重入鎖的參數(shù)進行初始化,默認false,另外初始化了notEmpty、notFull兩個信號量。
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue(i * 2 * 10);
        //1. 同步阻塞隊列 (put,take),直接提交。直接提交策略表示線程池不對任務進行緩存。新進任務直接提交給線程池,當線程池中沒有空閑線程時,創(chuàng)建一個新的線程處理此任務。
        // 這種策略需要線程池具有無限增長的可能性。實現(xiàn)為:SynchronousQueue
        //2. 有界隊列。當線程池中線程達到corePoolSize時,新進任務被放在隊列里排隊等待處理。有界隊列(如ArrayBlockingQueue)有助于防止資源耗盡,
        // 但是可能較難調(diào)整和控制。隊列大小和最大池大小可能需要相互折衷:使用大型隊列和小型池可以最大限度地降低 CPU 使用率、操作系統(tǒng)資源和上下文切換開銷,
        // 但是可能導致人工降低吞吐量。如果任務頻繁阻塞(例如,如果它們是 I/O 邊界),則系統(tǒng)可能為超過您許可的更多線程安排時間。使用小型隊列通常要求較大的池大小,
        // CPU 使用率較高,但是可能遇到不可接受的調(diào)度開銷,這樣也會降低吞吐量。
        //3. 無界隊列。使用無界隊列(例如,不具有預定義容量的 LinkedBlockingQueue)將導致在所有 corePoolSize 線程都忙時新任務在隊列中等待。
        // 這樣,創(chuàng)建的線程就不會超過 corePoolSize。(因此,maximumPoolSize 的值也就無效了。)當每個任務完全獨立于其他任務,即任務執(zhí)行互不影響時,
        // 適合于使用無界隊列;例如,在 Web 頁服務器中。這種排隊可用于處理瞬態(tài)突發(fā)請求,當命令以超過隊列所能處理的平均數(shù)連續(xù)到達時,此策略允許無界線程具有增長的可能性。
 
        //線程工廠
        //defaultThreadFactory()
        //返回用于創(chuàng)建新線程的默認線程工廠。
        //privilegedThreadFactory()
        //返回一個用于創(chuàng)建與當前線程具有相同權限的新線程的線程工廠。
        ThreadFactory threadFactory =Executors.defaultThreadFactory();
        //拒絕執(zhí)行處理器
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
        //創(chuàng)建線程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        return threadPoolExecutor;
    }
}
 

7.jdk自帶的四種線程池創(chuàng)建方式

// 第一種線程池:固定個數(shù)的線程池,可以為每個CPU核綁定一定數(shù)量的線程數(shù)
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(processors * 2);
// 緩存線程池,無上限
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 單一線程池,永遠會維護存在一條線程
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 固定個數(shù)的線程池,可以執(zhí)行延時任務,也可以執(zhí)行帶有返回值的任務。
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

8.調(diào)用線程池的線程案例

public List<AccountRecordVO> requestTest() throws ExecutionException, InterruptedException {
        List<String> ids = Lists.newArrayList();
        ids.add("1");
        ids.add("2");
        ids.add("3");
        ids.add("4");
        //有返回值的情況,定義接收返回值
        List<AccountRecordVO> futureList2 = Lists.newArrayList();
        //分布式計數(shù)器,若業(yè)務不需要則可以不定義
        CountDownLatch countDownLatch = new CountDownLatch(ids.size());
        for (String id : ids) {
            //調(diào)用線程池的線程執(zhí)行任務
            threadPoolTaskExecutor.submit(new Runnable() {
                @Override
                public void run() {
                    test(Lists.newArrayList(id),futureList2);
                    //計數(shù)器-1
                    countDownLatch.countDown();
                }
            });
        }
        //await阻塞,直到計數(shù)器為0
        countDownLatch.await();
        System.out.println("主線程"+"====");
        return futureList2;
    }
 
    public List<AccountRecordVO> test(List<String> ids, List<AccountRecordVO> list2){
        //隨便寫的業(yè)務邏輯代碼,無實際意義,僅作演示
        System.out.println("線程體" + "====");
        List<AccountRecordVO> accountRecordVOS = Lists.newArrayList();
        int i = 0;
        AccountRecordVO accountRecordVO = new AccountRecordVO();
        accountRecordVO.setUserId("123");
        accountRecordVO.setAmount(12333);
        for (String id : ids){
            accountRecordVOS.add(accountRecordVO);
            list2.add(accountRecordVO);
        }
        try{
            Thread.sleep(Long.valueOf("1000"));
        }catch (Exception e){
            log.error(e.getMessage());
        }
        System.out.println("線程體結束" + "====");
        return accountRecordVOS;
    }

到此這篇關于Java中的線程池ThreadPoolExecutor深入解析的文章就介紹到這了,更多相關Java線程池ThreadPoolExecutor內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Springboot 整合 Java DL4J 實現(xiàn)時尚穿搭推薦系統(tǒng)(實例代碼)

    Springboot 整合 Java DL4J 實現(xiàn)時尚穿搭推薦系統(tǒng)(實例代碼)

    本文介紹了如何使用SpringBoot和JavaDeeplearning4j框架搭建一個時尚穿搭推薦系統(tǒng),文章詳細闡述了系統(tǒng)的技術架構、數(shù)據(jù)集格式、Maven依賴配置、模型訓練和預測代碼實現(xiàn),以及單元測試和預期輸出結果
    2024-10-10
  • 如何在Java中創(chuàng)建線程通信的四種方式你知道嗎

    如何在Java中創(chuàng)建線程通信的四種方式你知道嗎

    開發(fā)中不免會遇到需要所有子線程執(zhí)行完畢通知主線程處理某些邏輯的場景?;蛘呤蔷€程 A 在執(zhí)行到某個條件通知線程 B 執(zhí)行某個操作。下面我們來一起學習如何解決吧
    2021-09-09
  • SpringBoot項目中出現(xiàn)不同端口跨域問題的解決方法

    SpringBoot項目中出現(xiàn)不同端口跨域問題的解決方法

    這篇文章主要介紹了SpringBoot項目中出現(xiàn)不同端口跨域問題的解決方法,文中介紹了兩種解決方法,并給出了詳細的代碼供大家參考,具有一定的參考價值,需要的朋友可以參考下
    2024-03-03
  • Mybatis如何解決sql中l(wèi)ike通配符模糊匹配問題

    Mybatis如何解決sql中l(wèi)ike通配符模糊匹配問題

    這篇文章主要介紹了Mybatis如何解決sql中l(wèi)ike通配符模糊匹配問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 淺談Maven包沖突的原理及解決方法

    淺談Maven包沖突的原理及解決方法

    這篇文章主要介紹了淺談Maven包沖突的原理及解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • java多線程模擬實現(xiàn)售票功能

    java多線程模擬實現(xiàn)售票功能

    這篇文章主要為大家詳細介紹了java多線程模擬實現(xiàn)售票功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 總結Java常用到的六個加密技術和代碼

    總結Java常用到的六個加密技術和代碼

    大家要記住現(xiàn)代密碼學最重要的原則柯克霍夫原則:數(shù)據(jù)的安全基于密鑰而不是算法的保密。也就是說即使密碼系統(tǒng)的任何細節(jié)已為人悉知,只要密匙未洩漏,它也應是安全的。這篇文章給大家介紹了6個常用的加密技術和代碼。
    2016-07-07
  • 詳解在SpringBoot中@Transactional事物操作和事物無效問題排查

    詳解在SpringBoot中@Transactional事物操作和事物無效問題排查

    這篇文章主要介紹了詳解在SpringBoot中@Transactional事物操作和事物無效問題排查,本文詳細的介紹了SpringBoot中集成使用@Transactional注解操作事物以及事物開啟后無效的問題排查,需要的朋友可以參考下
    2021-06-06
  • Java泛型的繼承和實現(xiàn)操作示例

    Java泛型的繼承和實現(xiàn)操作示例

    這篇文章主要介紹了Java泛型的繼承和實現(xiàn)操作,結合實例形式分析了java泛型類的繼承以及泛型接口的實現(xiàn)相關操作技巧,需要的朋友可以參考下
    2019-08-08
  • idea編譯器使用git拉取、提交非常慢的原因分析及解決

    idea編譯器使用git拉取、提交非常慢的原因分析及解決

    換電腦后IDEA使用Git操作卡頓,經(jīng)排查發(fā)現(xiàn)殺毒軟件誤判runnerw.exe為病毒,解決方法:重命名該文件或關閉Windows實時保護,重啟后Git速度顯著提升
    2025-09-09

最新評論

赫章县| 建瓯市| 定兴县| 宁德市| 灌云县| 龙岩市| 汉川市| 济宁市| 团风县| 湟中县| 广南县| 哈巴河县| 手机| 广南县| 辽阳市| 宿迁市| 长丰县| 荥阳市| 鸡泽县| 大邑县| 东安县| 宝兴县| 连江县| 科尔| 永州市| 新宁县| 敖汉旗| 太谷县| 平安县| 盘山县| 龙泉市| 新田县| 盐源县| 永和县| 福建省| 东明县| 岳池县| 沐川县| 天镇县| 克东县| 普洱|