SpringBoot配置線程池的實現(xiàn)示例
一.線程池簡介
1.1.什么是線程池
線程池是一種利用池化技術(shù)思想來實現(xiàn)的線程管理技術(shù),主要是為了復(fù)用線程、便利地管理線程和任務(wù)、并將線程的創(chuàng)建和任務(wù)的執(zhí)行解耦開來。我們可以創(chuàng)建線程池來復(fù)用已經(jīng)創(chuàng)建的線程來降低頻繁創(chuàng)建和銷毀線程所帶來的資源消耗。在JAVA中主要是使用ThreadPoolExecutor類來創(chuàng)建線程池,并且JDK中也提供了Executors工廠類來創(chuàng)建線程池(不推薦使用)。
1.2.線程池的優(yōu)點
降低資源消耗,復(fù)用已創(chuàng)建的線程來降低創(chuàng)建和銷毀線程的消耗。提高響應(yīng)速度,任務(wù)到達時,可以不需要等待線程的創(chuàng)建立即執(zhí)行。提高線程的可管理性,使用線程池能夠統(tǒng)一的分配、調(diào)優(yōu)和監(jiān)控。
1.3.線程池五種狀態(tài)
線程池ThreadPoolExecutor分別有五種狀態(tài)分別為:RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED使用一個AtomicInteger類型的ctl字段來描述線程池地運行狀態(tài)和線程數(shù)量,通過ctl的高三位來表示線程池的5種狀態(tài),低29位表示線程池中現(xiàn)有的線程數(shù)量。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
/**
* 線程池線程數(shù)地bit數(shù)
*/
private static final int COUNT_BITS = Integer.SIZE - 3;
/**
* 線程池中最大線程容量
*/
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
/**
* 表示可接受新任務(wù),且可執(zhí)行隊列中的任務(wù);
*/
private static final int RUNNING = -1 << COUNT_BITS;
/**
* 表示不接受新任務(wù),但可執(zhí)行隊列中的任務(wù);
*/
private static final int SHUTDOWN = 0 << COUNT_BITS;
/**
* 表示不接受新任務(wù),且不再執(zhí)行隊列中的任務(wù),且中斷正在執(zhí)行的任務(wù);
*/
private static final int STOP = 1 << COUNT_BITS;
/**
* 所有任務(wù)已經(jīng)中止,且工作線程數(shù)量為0,最后變遷到這個狀態(tài)的線程將
* 要執(zhí)行terminated()鉤子方法,只會有一個線程執(zhí)行這個方法;
*/
private static final int TIDYING = 2 << COUNT_BITS;
/**
* TERMINATED,中止?fàn)顟B(tài),已經(jīng)執(zhí)行完terminated()鉤子方法;
*/
private static final int TERMINATED = 3 << COUNT_BITS;線程池狀態(tài)之間的流轉(zhuǎn)圖如下所示

1.4.線程池處理流程
線程池處理流程代碼如下所示
/**
* 在將來某個時候執(zhí)行給定的任務(wù)。該任務(wù)可以在新線程中執(zhí)行,也可以在現(xiàn)有的池線程中執(zhí)行。如果由于此執(zhí)行
* 器已關(guān)閉或已達到其容量,任務(wù)無法提交執(zhí)行,則由當(dāng)前RejectedExecutionHandler處理該任務(wù)。
* Params:
* 命令–要執(zhí)行的任務(wù)
* Throws:
* RejectedExecutionException–如果任務(wù)無法接受執(zhí)行,則由RejectedExecutionHandler自行決定
* NullPointerException–如果命令為null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
分三步走:
1.如果運行的線程少于corePoolSize,請嘗試以給定的命令作為第一個任務(wù)來啟動一個新線程。
對addWorker的調(diào)用原子地檢查runState和workerCount,因此,通過返回false,可以防止
在不應(yīng)該添加線程的情況下添加線程的錯誤警報。
2.如果一個任務(wù)可以成功排隊,那么我們?nèi)匀恍枰屑殭z查我們是否應(yīng)該添加一個線程(因為自上
次檢查以來已有的線程已經(jīng)失效),或者池是否在進入該方法后關(guān)閉。因此,如果有必要,我們重
新檢查狀態(tài),如果停止,則回滾排隊,如果workerCount為0,則啟動一個新線程。
3.如果我們不能對任務(wù)進行排隊,那么我們嘗試添加一個新線程。如果它失敗了,我們知道線程池
被關(guān)閉或飽和了,所以拒絕了這項任務(wù)。
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
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);
} else if (!addWorker(command, false))
reject(command);
}線程池處理流程圖如下所示

二.開始配置
ThreadPoolTaskExecutor是spring core包中的,而ThreadPoolExecutor是JDK中的JUC。ThreadPoolTaskExecutor是對ThreadPoolExecutor進行了封裝處理。
2.1.依賴導(dǎo)入
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
2.2.配置application.properties文件
universe.thread.pool.executor.threadNamePrefix=threadPoolTaskExecutor- universe.thread.pool.executor.queueCapacity=100 universe.thread.pool.executor.rejectedExecutionHandler=java.util.concurrent.ThreadPoolExecutor$AbortPolicy universe.thread.pool.executor.keepAliveSeconds=60
2.3.創(chuàng)建PoolExecutorConfig.java
package com.temperature.humidity.system.config.thread;
import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Data
@Log4j2
public class PoolExecutorConfig {
/**
* 獲取CPU核數(shù)
*/
private static final int CPU_NUM;
/**
* 配置線程池的前綴
*/
@Value("${universe.thread.pool.executor.threadNamePrefix}")
private String threadNamePrefix;
/**
* 線程池的核心線程數(shù)。在沒有設(shè)置 allowCoreThreadTimeOut 為 true 的情況下,
* 核心線程會在線程池中一直存活,即使處于閑置狀態(tài)。
*/
private Integer corePoolSize;
/**
* 線程池中的任務(wù)隊列,通過線程池的 execute() 方法提交的 Runnable
* 對象會存儲在該隊列中。
*/
@Value("${universe.thread.pool.executor.queueCapacity}")
private Integer queueCapacity;
/**
* 線程池所能容納的最大線程數(shù)。當(dāng)活動線程(核心線程+非核心線程)達到這個數(shù)值后,
* 后續(xù)任務(wù)將會根據(jù) RejectedExecutionHandler 來進行拒絕策略處理。
*/
private Integer maxPoolSize;
/**
* 當(dāng)任務(wù)無法被執(zhí)行時(超過線程最大容量 maximum 并且 workQueue 已經(jīng)被排滿了)的處理策略,
* - AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常
* - DiscardPolicy:丟棄任務(wù),但是不拋出異常。
* - DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新提交被拒絕的任務(wù)
* - CallerRunsPolicy:由調(diào)用線程(提交任務(wù)的線程)處理該任務(wù)
*/
@Value("${universe.thread.pool.executor.rejectedExecutionHandler}")
private String rejectedExecutionHandler;
/**
* 非核心線程 閑置時的超時時長。超過該時長,非核心線程就會被回收。若線程池通設(shè)置
* 核心線程也允許 timeOut,即 allowCoreThreadTimeOut 為 true,則該時長
* 同樣會作用于核心線程,在超過aliveTime 時,核心線程也會被回收,AsyncTask
* 配置的線程池就是這樣設(shè)置的。
*/
@Value("${universe.thread.pool.executor.keepAliveSeconds}")
private Integer keepAliveSeconds;
public PoolExecutorConfig() {
log.info("該臺服務(wù)器的CPU核心數(shù)為{}", CPU_NUM);
this.corePoolSize = CPU_NUM + 1;
this.maxPoolSize = 2 * CPU_NUM;
}
static {
CPU_NUM = Runtime.getRuntime().availableProcessors();
}
}2.4.創(chuàng)建OurPoolExecutor.java
package com.temperature.humidity.system.config.thread;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionHandler;
/**
* @description 線程池配置類
*/
@Configuration
@Log4j2
public class OurPoolExecutor {
@Autowired
private PoolExecutorConfig threadPoolExecutorConfig;
@Bean
public Executor threadPoolTaskExecutor() {
String threadNamePrefix = threadPoolExecutorConfig.getThreadNamePrefix();
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
try {
log.info("開始初始化線程池 -->threadPoolTaskExecutor");
taskExecutor.setThreadNamePrefix(threadNamePrefix);
taskExecutor.setCorePoolSize(threadPoolExecutorConfig.getCorePoolSize());
taskExecutor.setMaxPoolSize(threadPoolExecutorConfig.getMaxPoolSize());
taskExecutor.setQueueCapacity(threadPoolExecutorConfig.getQueueCapacity());
//通過反射獲取RejectedExecutionHandlerClass 的類模板
Class<?> rejectedExecutionHandlerClass = Class.forName(threadPoolExecutorConfig.getRejectedExecutionHandler());
//獲取RejectedExecutionHandlerClass類的實例
RejectedExecutionHandler rejectedExecutionHandler = (RejectedExecutionHandler) rejectedExecutionHandlerClass.newInstance();
taskExecutor.setRejectedExecutionHandler(rejectedExecutionHandler);
taskExecutor.setKeepAliveSeconds(threadPoolExecutorConfig.getKeepAliveSeconds());
//進行加載
taskExecutor.initialize();
log.info("初始化線程池完成:{}核心線程為{}-->", threadNamePrefix, taskExecutor.getCorePoolSize());
return taskExecutor;
} catch (Exception e) {
e.printStackTrace();
log.error("初始化線程池失敗:{}失敗原因為:{}", threadNamePrefix, e.getMessage());
return null;
}
}
}三.測試
我們配置線程池后啟動我們的SpringBoot項目,可以看到我們的控制臺打印出來了如下圖中圈中的日志,測試成功。

到此這篇關(guān)于SpringBoot配置線程池的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot 線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何在Spring Boot中實現(xiàn)異步處理與并發(fā)控制
本文我們將深入探討如何在Spring Boot中實現(xiàn)異步處理與并發(fā)控制,這一過程涉及到異步任務(wù)的執(zhí)行、線程池的配置、以及并發(fā)控制的實踐,以幫助我們提升應(yīng)用的性能和響應(yīng)能力,感興趣的朋友跟隨小編一起看看吧2024-07-07
springboot結(jié)合JWT實現(xiàn)單點登錄的示例
本文主要介紹了springboot結(jié)合JWT實現(xiàn)單點登錄的示例,包括生成Token、驗證Token及使用Redis存儲Token,具有一定的參考價值,感興趣的可以了解一下2025-01-01
通過prometheus監(jiān)控springboot程序運行狀態(tài)的操作流程
jmx_exporter用于從Java應(yīng)用程序中提取JMX指標(biāo),適用于SpringBoot應(yīng)用,通過下載jar包和配置文件,可以抓取JVM基礎(chǔ)指標(biāo),要獲取應(yīng)用級別指標(biāo),需要集成Prometheus客戶端庫并自定義指標(biāo),本文給大家介紹了如何通過prometheus監(jiān)控springboot程序運行狀態(tài)2025-02-02

