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

@EnableAsync

@Configuration

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教程可以点击直达!,欢迎收藏与转发支持!

代码示例

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
979044)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值