0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Spring 的線程池應(yīng)用

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-13 10:47 ? 次閱讀

我們在日常開發(fā)中,經(jīng)常跟多線程打交道,Spring 為我們提供了一個線程池方便我們開發(fā),它就是 ThreadPoolTaskExecutor ,接下來我們就來聊聊 Spring 的線程池吧。


使用@Async聲明多線程

SpringBoot 提供了注解 @Async 來使用線程池, 具體使用方法如下:

  1. 在啟動類(配置類)添加@EnableAsync來開啟線程池
  2. 在需要開啟子線程的方法上添加注解 @Async

下面是一個簡單的例子:

@Component
@EnableAsync
@EnableScheduling
public class ScheduleTask {

    @Async
    @Scheduled(fixedRate = 2000)
    public void testAsync1() {
        try {
            Thread.sleep(6000);
            System.out.println(LocalDateTime.now() + "--線程1:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Async
    @Scheduled(cron = "*/2 * * * * ?")
    public void testAsync2() {
        try {
            Thread.sleep(1000);
            System.out.println(LocalDateTime.now() + "--線程2:" + Thread.currentThread().getName());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

啟動項目,得到如下日志結(jié)果:

圖片

可以發(fā)現(xiàn)在當(dāng)前環(huán)境下 task-${id} 這個 id 并不是一直增長的,而是一直在復(fù)用 1-8。這個時候可能就會有的小伙伴們會比較好奇,默認(rèn)的不是 SimpleAsyncTaskExecutor 嗎?為什么從日志打印的效果上看像是一直在復(fù)用 8 個線程,難道用的是 ThreadPoolTaskExecutor?

原因是 SpringBoot2.1.0 版本后,新增了 TaskExecutionAutoConfiguration 配置類。其中聲明的默認(rèn)線程池就是 ThreadPoolTaskExecutor 。而 @Async 在選擇執(zhí)行器的時候會先去 IOC 容器中先找是否有 TaskExecutor 的 Bean對象,所以在當(dāng)前版本 SpringBoot 中,@Async 的默認(rèn) TaskExecutor 是 ThreadPoolTaskExecutor。

線程池配置

在 SpringBoot 項目中,我們可以在 yaml 或者 properties 配置文件中配置,或者使用 @Configuration 配置,下面演示配置方法。

  1. application.properties配置文件中配置
# 核心線程池數(shù)
spring.task.execution.pool.core-size=5
# 最大線程池數(shù)
spring.task.execution.pool.max-size=10
# 任務(wù)隊列的容量
spring.task.execution.pool.queue-capacity=5
# 非核心線程的存活時間
spring.task.execution.pool.keep-alive=60
# 線程池的前綴名稱
spring.task.execution.thread-name-prefix=test-task-
  1. 配置類中配置
@Bean(name = "myThreadPoolTaskExecutor")
public ThreadPoolTaskExecutor getMyThreadPoolTaskExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    int i = Runtime.getRuntime().availableProcessors();
    taskExecutor.setCorePoolSize(i * 2);
    taskExecutor.setMaxPoolSize(i * 2);
    taskExecutor.setQueueCapacity(i * 2 * 100);
    taskExecutor.setKeepAliveSeconds(60);
    taskExecutor.setThreadNamePrefix("my-task-");
    taskExecutor.initialize();
    return taskExecutor;
}

拒絕策略

RejectedExectutionHandler 參數(shù)字段用于配置絕策略,常用拒絕策略如下

  • AbortPolicy:用于被拒絕任務(wù)的處理程序,它將拋出RejectedExecutionException
  • CallerRunsPolicy:用于被拒絕任務(wù)的處理程序,它直接在execute方法的調(diào)用線程中運行被拒絕的任務(wù)。
  • DiscardOldestPolicy:用于被拒絕任務(wù)的處理程序,它放棄最舊的未處理請求,然后重試execute。
  • DiscardPolicy:用于被拒絕任務(wù)的處理程序,默認(rèn)情況下它將丟棄被拒絕的任務(wù)。

處理流程

  1. 查看核心線程池是否已滿,不滿就創(chuàng)建一條線程執(zhí)行任務(wù),否則執(zhí)行第2步。
  2. 查看任務(wù)隊列是否已滿,不滿就將任務(wù)存儲在任務(wù)隊列中,否則執(zhí)行第3步。
  3. 查看線程池是否已滿,即就是是否達(dá)到最大線程池數(shù),不滿就創(chuàng)建一條線程執(zhí)行任務(wù),否則就按照策略處理無法執(zhí)行的任務(wù)。

使用注意

  1. 注解的方法必須是 public 方法。
  2. 方法一定要從另一個類中調(diào)用,也就是從類的外部調(diào)用,類的內(nèi)部調(diào)用是無效的,因為 @Transactional 和 @Async 注解的實現(xiàn)都是基于 Spring 的 AOP ,而 AOP 的實現(xiàn)是基于動態(tài)代理模式實現(xiàn)的。那么注解失效的原因就很明顯了,有可能因為調(diào)用方法的是對象本身而不是代理對象,因為沒有經(jīng)過 Spring 容器。
  3. 異步方法使用注解 @Async 的返回值只能為 void 或者 Future。

總結(jié)

上面簡單介紹了 Spring 自帶的線程池 ThreadPoolTaskExecutor 的配置和使用,并且講了線程池的參數(shù)和處理流程。當(dāng)然Spring提供了7個線程池的實現(xiàn),感興趣的可以自行了解~

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 文件
    +關(guān)注

    關(guān)注

    1

    文章

    551

    瀏覽量

    24559
  • 容器
    +關(guān)注

    關(guān)注

    0

    文章

    490

    瀏覽量

    21986
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    335

    瀏覽量

    14256
  • 線程池
    +關(guān)注

    關(guān)注

    0

    文章

    55

    瀏覽量

    6809
收藏 人收藏

    評論

    相關(guān)推薦

    跨平臺的線程組件--TP組件

    /銷毀代價是很高的。那么我們要怎么去設(shè)計多線程編程呢???答案:對于長駐的線程,我們可以創(chuàng)建獨立的線程去執(zhí)行。但是非長駐的線程,我們可以通過線程
    的頭像 發(fā)表于 04-06 15:39 ?777次閱讀

    Java中的線程包括哪些

    線程是用來統(tǒng)一管理線程的,在 Java 中創(chuàng)建和銷毀線程都是一件消耗資源的事情,線程可以重復(fù)
    的頭像 發(fā)表于 10-11 15:33 ?729次閱讀
    Java中的<b class='flag-5'>線程</b><b class='flag-5'>池</b>包括哪些

    線程是如何實現(xiàn)的

    線程的概念是什么?線程是如何實現(xiàn)的?
    發(fā)表于 02-28 06:20

    基于線程技術(shù)集群接入點的應(yīng)用研究

    本文在深入研究高級線程技術(shù)的基礎(chǔ)上,分析、研究了固定線程數(shù)目的線程線程數(shù)目動態(tài)變化的
    發(fā)表于 01-22 14:21 ?5次下載

    如何正確使用SpringBoot中的線程

    來自丨CSDN https://blog.csdn.net/m0_37701381/article/details/81072774 使用步驟 先創(chuàng)建一個線程的配置,讓Spring Boot加載
    的頭像 發(fā)表于 09-02 17:14 ?1891次閱讀

    基于Nacos的簡單動態(tài)化線程實現(xiàn)

    本文以Nacos作為服務(wù)配置中心,以修改線程核心線程數(shù)、最大線程數(shù)為例,實現(xiàn)一個簡單的動態(tài)化線程
    發(fā)表于 01-06 14:14 ?764次閱讀

    線程線程

    線程通常用于服務(wù)器應(yīng)用程序。 每個傳入請求都將分配給線程池中的一個線程,因此可以異步處理請求,而不會占用主線程,也不會延遲后續(xù)請求的處理
    的頭像 發(fā)表于 02-28 09:53 ?667次閱讀
    多<b class='flag-5'>線程</b>之<b class='flag-5'>線程</b><b class='flag-5'>池</b>

    Java線程核心原理

    看過Java線程源碼的小伙伴都知道,在Java線程池中最核心的類就是ThreadPoolExecutor,
    的頭像 發(fā)表于 04-21 10:24 ?753次閱讀

    細(xì)數(shù)線程的10個坑

    JDK開發(fā)者提供了線程的實現(xiàn)類,我們基于Executors組件,就可以快速創(chuàng)建一個線程
    的頭像 發(fā)表于 06-16 10:11 ?631次閱讀
    細(xì)數(shù)<b class='flag-5'>線程</b><b class='flag-5'>池</b>的10個坑

    線程線程怎么釋放

    線程分組看,pool名開頭線程占616條,而且waiting狀態(tài)也是616條,這個點就非??梢闪?,我斷定就是這個pool開頭線程導(dǎo)致的問題。我們先排查為何這個
    發(fā)表于 07-31 10:49 ?2066次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>的<b class='flag-5'>線程</b>怎么釋放

    線程基本概念與原理

    一、線程基本概念與原理 1.1 線程概念及優(yōu)勢 C++線程簡介
    的頭像 發(fā)表于 11-10 10:24 ?408次閱讀

    線程的基本概念

    線程的基本概念 不管線程是什么東西!但是我們必須知道線程被搞出來的目的就是:提高程序執(zhí)行效
    的頭像 發(fā)表于 11-10 16:37 ?424次閱讀
    <b class='flag-5'>線程</b><b class='flag-5'>池</b>的基本概念

    線程七大核心參數(shù)執(zhí)行順序

    線程是一種用于管理和調(diào)度線程執(zhí)行的技術(shù),通過將任務(wù)分配到線程池中的線程進(jìn)行處理,可以有效地控制并發(fā)線程
    的頭像 發(fā)表于 12-04 16:45 ?739次閱讀

    線程的創(chuàng)建方式有幾種

    線程是一種用于管理和調(diào)度線程的技術(shù),能夠有效地提高系統(tǒng)的性能和資源利用率。它通過預(yù)先創(chuàng)建一組線程并維護(hù)一個工作隊列,將任務(wù)提交給線程
    的頭像 發(fā)表于 12-04 16:52 ?660次閱讀

    什么是動態(tài)線程?動態(tài)線程的簡單實現(xiàn)思路

    因此,動態(tài)可監(jiān)控線程一種針對以上痛點開發(fā)的線程管理工具。主要可實現(xiàn)功能有:提供對 Spring 應(yīng)用內(nèi)
    的頭像 發(fā)表于 02-28 10:42 ?468次閱讀