Springboot应⽤中线程池配置详细教程(最新2021版)
前⾔:⽇常开发中我们常⽤ThreadPoolExecutor提供的线程池服务帮我们管理线程,在Springboot中更是提供了@Async注解来简化业务逻辑提交到线程池中执⾏的过程。由于Springboot中默认设置的corePoolSize=1和queyeCapacity=Integer.MAX_VALUE,相当于采⽤单线程处理所有任务,这就与多线程的⽬的背道⽽驰,所以这就要求我们在使⽤@Async注解时要配置线程池。本⽂就讲述下Springboot应⽤下的线程池配置。
背景知识:Springboot中通过使⽤ThreadPoolTaskExecutor这个JavaBean对象的corePoolSize(核⼼线程数)、maxPoolSize(最⼤线程数)、keepAliveSeconds(线程空闲时长)和queueCapacity(任务队列容量)属性来配置ThreadPoolExecutor,以上四个属性的作⽤⼤致如下:
新提交⼀个任务时的处理流程很明显:
1. 如果当前线程池的线程数还没有达到基本⼤⼩(poolSize < corePoolSize),⽆论是否有空闲的线程新增⼀个线程处理新提交的任务;
2. 如果当前线程池的线程数⼤于或等于基本⼤⼩(poolSize >= corePoolSize) 且任务队列未满时,就将新提交的任务提交到阻塞队列排
队,等候处理workQueue.offer(command);
3. 如果当前线程池的线程数⼤于或等于基本⼤⼩(poolSize >= corePoolSize) 且任务队列满时;
当前poolSize<maximumPoolSize,那么就新增线程来处理任务;
当前poolSize=maximumPoolSize,那么意味着线程池的处理能⼒已经达到了极限,此时需要拒绝新增加的任务。⾄于如何拒绝处理新增的任务,取决于线程池的饱和策略RejectedExecutionHandler。
好了,回到正⽂。⽬前配置Springboot线程池主要有两种⽅式:配置默认线程池和提供⾃定义线程池;毫⽆疑问,两种配置⽅式并⽆优劣。从使⽤⾓度来讲,由于⾃定义线程池是⾃定义即没有被Springboot默认使⽤的线程池,那么就需要通过@Async("⾃定义线程池bean对象名")的⽅式去使⽤,其它地⽅同默认线程池使⽤⽅式⼀致;下⾯通过⼀个简单的Springboot应⽤结合实际来展⽰:
1、新建⼀个Springboot项⽬,项⽬结构和l内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /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>
⼆、l中,⾃定义了线程池需要配置的四个属性,内容如下:
task:
pool:
corePoolSize: 10
maxPoolSize: 20
keepAliveSeconds: 300
queueCapacity: 50
三、在fig包中有三个类:TaskThreadPoolConfig类⽤来简化封装l配置的属
性,OverrideDefaultThreadPoolConfig类提供了配置默认线程池的⽅式,CustomizeThreadPoolConfig类则实现了⾃定义线程池,具体实现如下:
package fig.dto;
import lombok.Data;
import org.t.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 线程池配置属性类
* @author YuXD
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class TaskThreadPoolConfig {
/**
* 核⼼线程数
*/
private int corePoolSize;
/**
* 最⼤线程数
*/
private int maxPoolSize;
/**
* 线程空闲时间
*/
private int keepAliveSeconds;
/
**
* 任务队列容量(阻塞队列)
*/
private int queueCapacity;
}
package fig;
import fig.dto.TaskThreadPoolConfig;
slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import t.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.urrent.ThreadPoolTaskExecutor;
import urrent.Executor;
import urrent.ThreadPoolExecutor;
/**
* 重写默认线程池配置
* @author YuXD
*/
@Slf4j
@Configuration
@EnableAsync
public class OverrideDefaultThreadPoolConfig implements AsyncConfigurer {
@Autowired
private TaskThreadPoolConfig config;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核⼼线程池⼤⼩
executor.CorePoolSize());
//最⼤线程数
executor.MaxPoolSize());
/
/队列容量
executor.QueueCapacity());
//活跃时间
executor.KeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("default-thread-");
/*
当poolSize已达到maxPoolSize,如何处理新任务(是拒绝还是交由其它线程处理)
CallerRunsPolicy:不在新线程中执⾏任务,⽽是由调⽤者所在的线程来执⾏
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
/**
* 异步任务中异常处理
*
* @return
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> {
<("==========================" + ex.getMessage() + "=======================", ex); ("exception method:" + Name());
};
}
}
package fig;
import fig.dto.TaskThreadPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.urrent.ThreadPoolTaskExecutor;
import urrent.Executor;
import urrent.ThreadPoolExecutor;
/**
*
* ⾃定义下城
* @author : YuXD
*/
@Configuration
@EnableAsync
public class CustomizeThreadPoolConfig {
@Autowired
private TaskThreadPoolConfig config;
@Bean("customizeThreadPool")
public Executor doConfigCustomizeThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核⼼线程池⼤⼩
executor.CorePoolSize());
//最⼤线程数
executor.MaxPoolSize());
//队列容量
executor.QueueCapacity());
//活跃时间
executor.KeepAliveSeconds());
//线程名字前缀
executor.setThreadNamePrefix("customize-thread-");
/*
当poolSize已达到maxPoolSize,如何处理新任务(是拒绝还是交由其它线程处理)
CallerRunsPolicy:不在新线程中执⾏任务,⽽是由调⽤者所在的线程来执⾏
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
四、com.hugesoft.service包下的内容是从真实项⽬环境中提取出来的,IStatusAnalyseService定义了设备状态分析基础
Service,JJDeviceDataAnalyseManager,ZHUDeviceDataAnalyseManager,ZZDeviceDataAnalyseManager三个⼦类分别提供了默认实现,AbstractDeviceDataAnalyseManager提取了三个⼦类⽤到的公共⽅法,代码没难度,理解即可;需要尤其注意AbstractDeviceDataAnalyseManager的两个重载⽅法,分别采⽤默认线程池和⾃定义线程池的⽅式,注意使⽤的异同点,这点也就是默认线程池和⾃定义线程池适⽤上的唯⼀不同点。具体试下如下:
package com.hugesoft.service;
/**
* 参数分析基础Service,所有需要进⾏参数分析的都需要实现该接⼝
*
* @author YuXD
*/
public interface IStatusAnalyseService {
/**
* 设备状态解析处理
*
* @param start 开始时间
* @param end 截⽌时间
*/
void doStatusAnalyseHandle(String start, String end);
/**
* 设备状态解析处理
*
* @param end 截⽌时间
*/
void doStatusAnalyseHandle(String end);
/**
* 获取数据类别
*
* @return
*/
String getDataType();
}
package com.hugesoft.service.impl;
import com.hugesoft.service.IStatusAnalyseService;
import org.springframework.scheduling.annotation.Async;
import java.util.Random;
/**
* 抽象的设备数据分析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() + "执⾏了" + 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() + "执⾏了" + sleepSeconds + "秒"); }
}
package com.hugesoft.service.impl;
import org.springframework.stereotype.Service;
/**
* @description: 机加设备数据分析Service实现类
* @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: 铸造设备数据分析Service实现类
* @author: YuXD
* @create: 2020-06-18 22:56
**/
@Service("ZHU")
public class ZHUDeviceDataAnalyseManager extends AbstractDeviceDataAnalyseManager {
springboot aop@Override
public String getDataType() {
return "铸造";
}
}
package com.hugesoft.service.impl;
import org.springframework.stereotype.Service;
/**
* @description: 总装设备数据分析Service实现类
* @author: YuXD
* @create: 2020-06-18 22:56
**/
@Service("ZZ")
public class ZZDeviceDataAnalyseManager extends AbstractDeviceDataAnalyseManager {
@Override
public String getDataType() {
return "总装";
}
}
五、最后看⼀下Springboot启动类实现;该类既是启动类也是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;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论