Springboot應用中線程池配置詳細教程(最新2021版)
前言:日常開發(fā)中我們常用ThreadPoolExecutor提供的線程池服務幫我們管理線程,在Springboot中更是提供了@Async注解來簡化業(yè)務邏輯提交到線程池中執(zhí)行的過程。由于Springboot中默認設置的corePoolSize=1和queyeCapacity=Integer.MAX_VALUE,相當于采用單線程處理所有任務,這就與多線程的目的背道而馳,所以這就要求我們在使用@Async注解時要配置線程池。本文就講述下Springboot應用下的線程池配置。
背景知識:Springboot中通過使用ThreadPoolTaskExecutor這個JavaBean對象的corePoolSize(核心線程數(shù))、maxPoolSize(最大線程數(shù))、keepAliveSeconds(線程空閑時長)和queueCapacity(任務隊列容量)屬性來配置ThreadPoolExecutor,以上四個屬性的作用大致如下:
新提交一個任務時的處理流程很明顯:
- 如果當前線程池的線程數(shù)還沒有達到基本大小(poolSize < corePoolSize),無論是否有空閑的線程新增一個線程處理新提交的任務;
- 如果當前線程池的線程數(shù)大于或等于基本大小(poolSize >= corePoolSize) 且任務隊列未滿時,就將新提交的任務提交到阻塞隊列排隊,等候處理workQueue.offer(command);
- 如果當前線程池的線程數(shù)大于或等于基本大小(poolSize >= corePoolSize) 且任務隊列滿時;
- 當前poolSize<maximumPoolSize,那么就新增線程來處理任務;
- 當前poolSize=maximumPoolSize,那么意味著線程池的處理能力已經達到了極限,此時需要拒絕新增加的任務。至于如何拒絕處理新增的任務,取決于線程池的飽和策略RejectedExecutionHandler。
好了,回到正文。目前配置Springboot線程池主要有兩種方式:配置默認線程池和提供自定義線程池;毫無疑問,兩種配置方式并無優(yōu)劣。從使用角度來講,由于自定義線程池是自定義即沒有被Springboot默認使用的線程池,那么就需要通過@Async("自定義線程池bean對象名")的方式去使用,其它地方同默認線程池使用方式一致;下面通過一個簡單的Springboot應用結合實際來展示:
1、新建一個Springboot項目,項目結構和pom.xml內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.17.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hugesoft</groupId>
<artifactId>springboot-async</artifactId>
<version>0.0.1</version>
<name>springboot-async</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二、application.yml中,自定義了線程池需要配置的四個屬性,內容如下:
task: pool: corePoolSize: 10 maxPoolSize: 20 keepAliveSeconds: 300 queueCapacity: 50
三、在com.hugesoft.config包中有三個類:TaskThreadPoolConfig類用來簡化封裝application.yml配置的屬性,OverrideDefaultThreadPoolConfig類提供了配置默認線程池的方式,CustomizeThreadPoolConfig類則實現(xiàn)了自定義線程池,具體實現(xiàn)如下:
package com.hugesoft.config.dto;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 線程池配置屬性類
* @author YuXD
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class TaskThreadPoolConfig {
/**
* 核心線程數(shù)
*/
private int corePoolSize;
/**
* 最大線程數(shù)
*/
private int maxPoolSize;
/**
* 線程空閑時間
*/
private int keepAliveSeconds;
/**
* 任務隊列容量(阻塞隊列)
*/
private int queueCapacity;
}
package com.hugesoft.config;
import com.hugesoft.config.dto.TaskThreadPoolConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 重寫默認線程池配置
* @author YuXD
*/
@Slf4j
@Configuration
@EnableAsync
public class OverrideDefaultThreadPoolConfig implements AsyncConfigurer {
@Autowired
private TaskThreadPoolConfig config;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心線程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大線程數(shù)
executor.setMaxPoolSize(config.getMaxPoolSize());
//隊列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活躍時間
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//線程名字前綴
executor.setThreadNamePrefix("default-thread-");
/*
當poolSize已達到maxPoolSize,如何處理新任務(是拒絕還是交由其它線程處理)
CallerRunsPolicy:不在新線程中執(zhí)行任務,而是由調用者所在的線程來執(zhí)行
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
/**
* 異步任務中異常處理
*
* @return
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
log.error("==========================" + ex.getMessage() + "=======================", ex);
log.error("exception method:" + method.getName());
};
}
}
package com.hugesoft.config;
import com.hugesoft.config.dto.TaskThreadPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
*
* 自定義下城
* @author : YuXD
*/
@Configuration
@EnableAsync
public class CustomizeThreadPoolConfig {
@Autowired
private TaskThreadPoolConfig config;
@Bean("customizeThreadPool")
public Executor doConfigCustomizeThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心線程池大小
executor.setCorePoolSize(config.getCorePoolSize());
//最大線程數(shù)
executor.setMaxPoolSize(config.getMaxPoolSize());
//隊列容量
executor.setQueueCapacity(config.getQueueCapacity());
//活躍時間
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
//線程名字前綴
executor.setThreadNamePrefix("customize-thread-");
/*
當poolSize已達到maxPoolSize,如何處理新任務(是拒絕還是交由其它線程處理)
CallerRunsPolicy:不在新線程中執(zhí)行任務,而是由調用者所在的線程來執(zhí)行
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
四、com.hugesoft.service包下的內容是從真實項目環(huán)境中提取出來的,IStatusAnalyseService定義了設備狀態(tài)分析基礎Service,JJDeviceDataAnalyseManager,ZHUDeviceDataAnalyseManager,ZZDeviceDataAnalyseManager三個子類分別提供了默認實現(xiàn),AbstractDeviceDataAnalyseManager提取了三個子類用到的公共方法,代碼沒難度,理解即可;需要尤其注意AbstractDeviceDataAnalyseManager的兩個重載方法,分別采用默認線程池和自定義線程池的方式,注意使用的異同點,這點也就是默認線程池和自定義線程池適用上的唯一不同點。具體試下如下:
package com.hugesoft.service;
/**
* 參數(shù)分析基礎Service,所有需要進行參數(shù)分析的都需要實現(xiàn)該接口
*
* @author YuXD
*/
public interface IStatusAnalyseService {
/**
* 設備狀態(tài)解析處理
*
* @param start 開始時間
* @param end 截止時間
*/
void doStatusAnalyseHandle(String start, String end);
/**
* 設備狀態(tài)解析處理
*
* @param end 截止時間
*/
void doStatusAnalyseHandle(String end);
/**
* 獲取數(shù)據類別
*
* @return
*/
String getDataType();
}
package com.hugesoft.service.impl;
import com.hugesoft.service.IStatusAnalyseService;
import org.springframework.scheduling.annotation.Async;
import java.util.Random;
/**
* 抽象的設備數(shù)據分析Manager
*
* @author YuXD
* @since 2020-06-18 22:47
*/
public abstract class AbstractDeviceDataAnalyseManager implements IStatusAnalyseService {
@Async("customizeThreadPool")
@Override
public void doStatusAnalyseHandle(String start, String end) {
int sleepSeconds = new Random().nextInt(3) + 1;
try {
Thread.sleep(sleepSeconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getDataType() + "在自定義線程" + Thread.currentThread().getName() + "執(zhí)行了" + sleepSeconds + "秒");
}
@Async
@Override
public void doStatusAnalyseHandle(String end) {
int sleepSeconds = new Random().nextInt(3) + 1;
try {
Thread.sleep(sleepSeconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getDataType() + "在默認線程" + Thread.currentThread().getName() + "執(zhí)行了" + sleepSeconds + "秒");
}
}
package com.hugesoft.service.impl;
import org.springframework.stereotype.Service;
/**
* @description: 機加設備數(shù)據分析Service實現(xiàn)類
* @author: YuXD
* @create: 2021-03-15 20:17
**/
@Service("JJ")
public class JJDeviceDataAnalyseManager extends AbstractDeviceDataAnalyseManager {
@Override
public String getDataType() {
return "機加";
}
}
package com.hugesoft.service.impl;
import org.springframework.stereotype.Service;
/**
* @description: 鑄造設備數(shù)據分析Service實現(xiàn)類
* @author: YuXD
* @create: 2020-06-18 22:56
**/
@Service("ZHU")
public class ZHUDeviceDataAnalyseManager extends AbstractDeviceDataAnalyseManager {
@Override
public String getDataType() {
return "鑄造";
}
}
package com.hugesoft.service.impl;
import org.springframework.stereotype.Service;
/**
* @description: 總裝設備數(shù)據分析Service實現(xiàn)類
* @author: YuXD
* @create: 2020-06-18 22:56
**/
@Service("ZZ")
public class ZZDeviceDataAnalyseManager extends AbstractDeviceDataAnalyseManager {
@Override
public String getDataType() {
return "總裝";
}
}
五、最后看一下Springboot啟動類實現(xiàn);該類既是啟動類也是Controller類,沒什么特別要說明的。
package com.hugesoft;
import com.hugesoft.service.IStatusAnalyseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@EnableAsync
@SpringBootApplication
public class SpringbootAsyncApplication {
@Autowired
private List<IStatusAnalyseService> statusAnalyseServiceList;
public static void main(String[] args) {
SpringApplication.run(SpringbootAsyncApplication.class, args);
}
@GetMapping("/sayHelloAsync")
public String sayHelloAsync() {
for (IStatusAnalyseService statusAnalyseService : statusAnalyseServiceList) {
// 采用自定義線程池
statusAnalyseService.doStatusAnalyseHandle(null, null);
// 采用默認線程池
statusAnalyseService.doStatusAnalyseHandle(null);
}
return "Hello, Async!";
}
}
六、最后啟動main方法,通過瀏覽器地址欄訪問 http://localhost:8080/sayHelloAsync,發(fā)現(xiàn)秒出現(xiàn)如下頁面,且控制臺會出現(xiàn)如下內容,說明我們配置的默認線程池和自定義線程池都起作用了,到此,配置成功


到此這篇關于Springboot應用中線程池配置教程(2021版)的文章就介紹到這了,更多相關Springboot線程池配置內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mybatis plus 關聯(lián)數(shù)據庫排除不必要字段方式
這篇文章主要介紹了mybatis plus 關聯(lián)數(shù)據庫排除不必要字段方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
StringUtils里的isEmpty方法和isBlank方法的區(qū)別詳解
這篇文章主要介紹了StringUtils里的isEmpty方法和isBlank方法的區(qū)別詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-04-04
Spring boot 使用JdbcTemplate訪問數(shù)據庫
SpringBoot 是為了簡化 Spring 應用的創(chuàng)建、運行、調試、部署等一系列問題而誕生的產物。本文重點給大家介紹spring boot 使用JdbcTemplate訪問數(shù)據庫,需要的朋友可以參考下2018-05-05

