一、内容为一个Demo,也是记录一下我自己在学习的过程中的记录,防止后面忘记了可以找到看一看(自己写的终归是好看懂写),没有跟项目实战逻辑结合,需要的可以自己敲一遍,知道个流程(介意请右转),毕竟springBoot为我们封装了很多,只需要简单的配置就可以使用。本文内容我也是根据大佬的博客学习敲的(至于这位大佬是不是原创就不是我关心的了,点击跳转)
二、下面开始正文
1.创建个springboot项目吧,使用idea的spring Initializr一键创建,可以使用**https://start.aliyun.com/**的url,这个比默认的快一点,默认的会创建失败。(不信邪的亲身经历过的痛苦,阿里云的真香)
2.修改下application.yml配置
server:
port: 8097
# 线程池默认配置
task:
pool:
corePoolSize: 5
maxPoolSize: 5
keepAliveSeconds: 300
queueCapacity: 1000
3.创建线程池配置类
@Component
@ConfigurationProperties(prefix = "task.pool")
public class TaskThreadPoolConfig {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
/* GetAndSet方法 */
}
4.创建线程池信息打印类
package com.zhitu.thread.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @Author HO
* @Package com.zhitu.thread.ThreadPool
* @Description 创建ThreadPoolTaskExecutor子类 打印线程池使用情况
* @Date 2020/8/5 13:32
* @Version 1.0.0
*/
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
//定义全局日志打印变量
private static final Logger LOGGER = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);
//创建方法打印线程池使用情况
private void showThreadPoolInfo(String prefix) {
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();
//判断
if (threadPoolExecutor == null) {
return;
}
//打印线程池使用日志
LOGGER.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
this.getThreadNamePrefix(),
prefix,
threadPoolExecutor.getTaskCount(), //任务总数
threadPoolExecutor.getCompletedTaskCount(), //已完成任务数
threadPoolExecutor.getActiveCount(), //活跃线程数
threadPoolExecutor.getQueue().size() //队列大小
);
}
/**
*@Description 重写ThreadPoolTaskExecutor的以下六个方法
*@Param [task]
*@Return void
*@Author Mr.Chen
*@Date 2020/8/5 13:38
*/
@Override
public void execute(Runnable task) {
showThreadPoolInfo("1. do execute");
super.execute(task);
}
@Override
public void execute(Runnable task, long startTimeout) {
showThreadPoolInfo("2. do execute");
super.execute(task, startTimeout);
}
@Override
public Future<?> submit(Runnable task) {
showThreadPoolInfo("1. do submit");
return super.submit(task);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
showThreadPoolInfo("2. do submit");
return super.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
showThreadPoolInfo("1. do submitListenable");
return super.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
showThreadPoolInfo("2. do submitListenable");
return super.submitListenable(task);
}
}
5.创建线程池类
@Configuration
@EnableAsync
public class TaskExecutePool {
@Autowired
private TaskThreadPoolConfig taskThreadPoolConfig;
@Bean
public Executor myTaskAsyncPool() {
//创建线程池对象
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//这里使用我们自己创建的线程池对象类,可打印线程池使用日志信息
VisiableThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//设置线程池属性
executor.setCorePoolSize(taskThreadPoolConfig.getCorePoolSize());
executor.setMaxPoolSize(taskThreadPoolConfig.getMaxPoolSize());
executor.setKeepAliveSeconds(taskThreadPoolConfig.getKeepAliveSeconds());
executor.setQueueCapacity(taskThreadPoolConfig.getQueueCapacity());
//设置线程池前缀(可配置到yml文件中进行动态读取)
executor.setThreadNamePrefix("myExecutor-");
// setRejectedExecutionHandler:当pool已经达到线程池最大线程max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
注意:实用配置类读取数据的话,需要在启动类开启读取配置类注解跟异步注解
@EnableAsync //开启异步支持
@SpringBootApplication
@EnableConfigurationProperties({TaskThreadPoolConfig.class})//开启配置类属性支持
public class ThreadApplication {
public static void main(String[] args) {
SpringApplication.run(ThreadApplication.class, args);
}
}
当然也可以接在线程池类使用注解 @Value("${task.pool.corePoolSize}")来获取yml文件的配置数据,
这样就不需要使用创建配置类来获取数据(第三步可省略)
例如:
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
@Value("${task.pool.corePoolSize}")
private int corePoolSize;
@Value("${task.pool.maxPoolSize}")
private int maxPoolSize;
@Value("${task.pool.queueCapacity}")
private int queueCapacity;
@Value("${task.pool.keepAliveSeconds}")
private int keepAliveSeconds;
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor");
// ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置
executor.setKeepAliveSeconds(keepAliveSeconds);
//配置线程池中的线程的名称前缀 也可以从yml配置读取
executor.setThreadNamePrefix("myExecutor-");
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
使用这种读取方法的启动类上则不需要加上开启配置读取注解
6.以上操作在springboot项目中的线程池配置就完成了,下面就是controller–>service–>dao的逻辑了。这里简单写个测试
①controller代码:
package com.zhitu.thread.controller;
import com.zhitu.thread.service.AsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Author HO
* @Package com.zhitu.thread.controller
* @Description
* @Date 2020/8/5 11:03
* @Version 1.0.0
*/
@RestController
public class AsyncController {
protected static final Logger LOGGER = LoggerFactory.getLogger(AsyncController.class);
@Autowired
private AsyncService asyncService;
@RequestMapping("/")
public String submit() {
LOGGER.info("start submit");
//调用service
this.asyncService.executeAsync();
//调用结束 打印日志
LOGGER.info("end submit");
return "success";
}
}
②service代码:
package com.zhitu.thread.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* @Author HO
* @Package com.zhitu.thread.service
* @Description
* @Date 2020/8/5 10:58
* @Version 1.0.0
*/
@Service
public class AsyncService {
protected static final Logger logger = LoggerFactory.getLogger(AsyncService.class);
@Async("myTaskAsyncPool")//myTaskAsyncPool为线程池配置类里面的方法,如果使用@Value注解读取配置,则应该改为asyncServiceExecutor(同上面代码的方法名称,可以往上查看)
public void executeAsync() {
logger.info("start AsyncService");
try {
//逻辑操作
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
logger.info("end AsyncService");
}
}
7.以上就是配置完成了,可启动项目访问http://localhost:8097/,按F5刷新页面,查看idea控制台信息
531 INFO 46040 --- [nio-8097-exec-1] c.z.thread.controller.AsyncController : start submit
2020-08-05 13:57:05.531 INFO 46040 --- [nio-8097-exec-1] c.z.t.T.VisiableThreadPoolTaskExecutor : myExecutor-, 2. do submit,taskCount [40], completedTaskCount [26], activeCount [5], queueSize [9]
2020-08-05 13:57:05.532 INFO 46040 --- [nio-8097-exec-1] c.z.thread.controller.AsyncController : end submit
2020-08-05 13:57:05.591 INFO 46040 --- [nio-8097-exec-2] c.z.thread.controller.AsyncController : start submit
2020-08-05 13:57:05.591 INFO 46040 --- [nio-8097-exec-2] c.z.t.T.VisiableThreadPoolTaskExecutor : myExecutor-, 2. do submit,taskCount [41], completedTaskCount [26], activeCount [5], queueSize [10]
2020-08-05 13:57:05.591 INFO 46040 --- [nio-8097-exec-2] c.z.thread.controller.AsyncController : end submit
2020-08-05 13:57:05.675 INFO 46040 --- [ myExecutor-2] com.zhitu.thread.service.AsyncService : end AsyncService
2020-08-05 13:57:05.676 INFO 46040 --- [ myExecutor-2] com.zhitu.thread.service.AsyncService : start AsyncService
2020-08-05 13:57:05.756 INFO 46040 --- [nio-8097-exec-4] c.z.thread.controller.AsyncController : start submit
2020-08-05 13:57:05.756 INFO 46040 --- [nio-8097-exec-4] c.z.t.T.VisiableThreadPoolTaskExecutor : myExecutor-, 2. do submit,taskCount [42], completedTaskCount [27], activeCount [5], queueSize [10]
2020-08-05 13:57:05.757 INFO 46040 --- [nio-8097-exec-4] c.z.thread.controller.AsyncController : end submit
2020-08-05 13:57:05.844 INFO 46040 --- [ myExecutor-3] com.zhitu.thread.service.AsyncService : end AsyncService
2020-08-05 13:57:05.844 INFO 46040 --- [ myExecutor-3] com.zhitu.thread.service.AsyncService : start AsyncService
2020-08-05 13:57:05.951 INFO 46040 --- [nio-8097-exec-3] c.z.thread.controller.AsyncController : start submit
2020-08-05 13:57:05.951 INFO 46040 --- [nio-8097-exec-3] c.z.t.T.VisiableThreadPoolTaskExecutor : myExecutor-, 2. do submit,taskCount [43], completedTaskCount [28], activeCount [5], queueSize [10]
2020-08-05 13:57:05.951 INFO 46040 --- [nio-8097-exec-3] c.z.thread.controller.AsyncController : end submit
2020-08-05 13:57:06.015 INFO 46040 --- [ myExecutor-4] com.zhitu.thread.service.AsyncService : end AsyncService
2020-08-05 13:57:06.015 INFO 46040 --- [ myExecutor-4] com.zhitu.thread.service.AsyncService : start AsyncService
2020-08-05 13:57:06.101 INFO 46040 --- [nio-8097-exec-5] c.z.thread.controller.AsyncController : start submit
2020-08-05 13:57:06.101 INFO 46040 --- [nio-8097-exec-5] c.z.t.T.VisiableThreadPoolTaskExecutor : myExecutor-, 2. do submit,taskCount [44], completedTaskCount [29], activeCount [5], queueSize [10]
2020-08-05 13:57:06.101 INFO 46040 --- [nio-8097-exec-5] c.z.thread.controller.AsyncController : end submit
2020-08-05 13:57:06.171 INFO 46040 --- [ myExecutor-5] com.zhitu.thread.service.AsyncService : end AsyncService
2020-08-05 13:57:06.171 INFO 46040 --- [ myExecutor-5] com.zhitu.thread.service.AsyncService : start AsyncService
2020-08-05 13:57:06.275 INFO 46040 --- [nio-8097-exec-6] c.z.thread.controller.AsyncController : start submit
2020-08-05 13:57:06.275 INFO 46040 --- [nio-8097-exec-6] c.z.t.T.VisiableThreadPoolTaskExecutor : myExecutor-, 2. do submit,taskCount [45], completedTaskCount [30], activeCount [5], queueSize [10]
2020-08-05 13:57:06.275 INFO 46040 --- [nio-8097-exec-6] c.z.thread.controller.AsyncController : end submit
具体的控制台输入内容大家可以自行查看。
主要注意这里的打印语句:
myExecutor-, 2. do submit,taskCount [44], completedTaskCount [29], activeCount [5], queueSize [10]
taskCount:总任务数(就是你点了多少F5)
completedTaskCount:已完成任务数
activeCount:活跃线程数(这个是yml文件中配置的最大线程数,大家可更改配置文件的参数数据进行测试)
queueSize :队列数量(配置文件的最大队列等待数)
好啦 以上就是整个配置线程池的流程,本人也是初学者,菜鸟一枚,在此记录一下,方便以后有需要查看时有自己的思路,有错误之处还请各位大佬海涵,有需要可以去上面原文大佬那里学习。小弟在此谢过!!!!!!!!!!!!!看到现在辛苦了!!!!!!!!!!看不如自己动手敲一!!!!遍!!!!!!!!!拜拜了您嘞!!!!!!!!!!!!!!!!!!!!!!!!!