Spring Boot中有多个@Async异步任务时,记得做好线程池的隔离!(1)

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

public class TaskPoolConfig {

@Bean

public Executor taskExecutor1() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(2);

executor.setMaxPoolSize(2);

executor.setQueueCapacity(10);

executor.setKeepAliveSeconds(60);

executor.setThreadNamePrefix(“executor-1-”);

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

return executor;

}

@Bean

public Executor taskExecutor2() {

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

executor.setCorePoolSize(2);

executor.setMaxPoolSize(2);

executor.setQueueCapacity(10);

executor.setKeepAliveSeconds(60);

executor.setThreadNamePrefix(“executor-2-”);

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

return executor;

}

}

注意:这里特地用executor.setThreadNamePrefix设置了线程名的前缀,这样可以方便观察后面具体执行的顺序。

第二步:创建异步任务,并指定要使用的线程池名称

@Slf4j

@Component

public class AsyncTasks {

public static Random random = new Random();

@Async(“taskExecutor1”)

public CompletableFuture doTaskOne(String taskNo) throws Exception {

log.info(“开始任务:{}”, taskNo);

long start = System.currentTimeMillis();

Thread.sleep(random.nextInt(10000));

long end = System.currentTimeMillis();

log.info(“完成任务:{},耗时:{} 毫秒”, taskNo, end - start);

return CompletableFuture.completedFuture(“任务完成”);

}

@Async(“taskExecutor2”)

public CompletableFuture doTaskTwo(String taskNo) throws Exception {

log.info(“开始任务:{}”, taskNo);

long start = System.currentTimeMillis();

Thread.sleep(random.nextInt(10000));

long end = System.currentTimeMillis();

log.info(“完成任务:{},耗时:{} 毫秒”, taskNo, end - start);

return CompletableFuture.completedFuture(“任务完成”);

}

}

这里@Async注解中定义的taskExecutor1taskExecutor2就是线程池的名字。由于在第一步中,我们没有具体写两个线程池Bean的名称,所以默认会使用方法名,也就是taskExecutor1taskExecutor2

第三步:写个单元测试来验证下,比如下面这样:

@Slf4j

@SpringBootTest

public class Chapter77ApplicationTests {

@Autowired

private AsyncTasks asyncTasks;

@Test

public void test() throws Exception {

long start = System.currentTimeMillis();

// 线程池1

CompletableFuture task1 = asyncTasks.doTaskOne(“1”);

CompletableFuture task2 = asyncTasks.doTaskOne(“2”);

CompletableFuture task3 = asyncTasks.doTaskOne(“3”);

// 线程池2

CompletableFuture task4 = asyncTasks.doTaskTwo(“4”);

CompletableFuture task5 = asyncTasks.doTaskTwo(“5”);

CompletableFuture task6 = asyncTasks.doTaskTwo(“6”);

// 一起执行

CompletableFuture.allOf(task1, task2, task3, task4, task5, task6).join();

long end = System.currentTimeMillis();

log.info(“任务全部完成,总耗时:” + (end - start) + “毫秒”);

}

}

在上面的单元测试中,一共启动了6个异步任务,前三个用的是线程池1,后三个用的是线程池2。

先不执行,根据设置的核心线程2和最大线程数2,来分析一下,大概会是怎么样的执行情况?

  1. 线程池1的三个任务,task1和task2会先获得执行线程,然后task3因为没有可分配线程进入缓冲队列

  2. 线程池2的三个任务,task4和task5会先获得执行线程,然后task6因为没有可分配线程进入缓冲队列

  3. 任务task3会在task1或task2完成之后,开始执行

  4. 任务task6会在task4或task5完成之后,开始执行

分析好之后,执行下单元测试,看看是否是这样的:

2021-09-15 23:45:11.369 INFO 61670 — [ executor-1-1] com.didispace.chapter77.AsyncTasks : 开始任务:1

2021-09-15 23:45:11.369 INFO 61670 — [ executor-2-2] com.didispace.chapter77.AsyncTasks : 开始任务:5

2021-09-15 23:45:11.369 INFO 61670 — [ executor-2-1] com.didispace.chapter77.AsyncTasks : 开始任务:4

2021-09-15 23:45:11.369 INFO 61670 — [ executor-1-2] com.didispace.chapter77.AsyncTasks : 开始任务:2

2021-09-15 23:45:15.905 INFO 61670 — [ executor-2-1] com.didispace.chapter77.AsyncTasks : 完成任务:4,耗时:4532 毫秒

2021-09-15 23:45:15.905 INFO 61670 — [ executor-2-1] com.didispace.chapter77.AsyncTasks : 开始任务:6

2021-09-15 23:45:18.263 INFO 61670 — [ executor-1-2] com.didispace.chapter77.AsyncTasks : 完成任务:2,耗时:6890 毫秒

2021-09-15 23:45:18.263 INFO 61670 — [ executor-1-2] com.didispace.chapter77.AsyncTasks : 开始任务:3

2021-09-15 23:45:18.896 INFO 61670 — [ executor-2-2] com.didispace.chapter77.AsyncTasks : 完成任务:5,耗时:7523 毫秒

2021-09-15 23:45:19.842 INFO 61670 — [ executor-1-2] com.didispace.chapter77.AsyncTasks : 完成任务:3,耗时:1579 毫秒

2021-09-15 23:45:20.551 INFO 61670 — [ executor-1-1] com.didispace.chapter77.AsyncTasks : 完成任务:1,耗时:9178 毫秒

2021-09-15 23:45:24.117 INFO 61670 — [ executor-2-1] com.didispace.chapter77.AsyncTasks : 完成任务:6,耗时:8212 毫秒

2021-09-15 23:45:24.117 INFO 61670 — [ main] c.d.chapter77.Chapter77ApplicationTests : 任务全部完成,总耗时:12762毫秒

好了,今天的学习就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的Spring技术交流群,参与交流与讨论,更好的学习与进步!更多Spring Boot教程可以点击直达!,欢迎收藏与转发支持!

代码示例


本文的完整工程可以查看下面仓库中2.x目录下的chapter7-7工程:

最后

现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**

image
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**

[外链图片转存中…(img-9Fuj6UES-1714657768428)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值