Spring Boot注解@Async与线程池的配置

目录

使用异步注解创建异步任务

@Async注解

使用Demo

线程池配置

Spring Boot默认用于异步任务线程池配置

 线程池配置

 线程池隔离

为什么需要线程池隔离?

线程池隔离实现Demo

 线程池配置:

 异步任务:

测试demo

参考内容:


使用异步注解创建异步任务

@Async注解

异步注解,需要在 springboot主程序上配置@EnableAsync。

使用条件:任务本身之间不存在依赖关系

使用Demo

@Component
@Slf4j
public class AsyncTasksService {

    public static Random random = new Random();

    @Async
    public CompletableFuture<String> doTaskOne() throws Exception {
        log.info("doTaskOne()开始");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("doTaskOne()执行结束,耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskOne()执行结束");
    }
    @Async
    public CompletableFuture<String> doTaskTwo() throws Exception {
        log.info("doTaskTwo()开始");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("doTaskTwo()执行结束,耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskTwo()执行结束");
    }
    @Async
    public CompletableFuture<String> doTaskThree() throws Exception {
        log.info("doTaskThree()开始");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("doTaskThree()执行结束,耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskThree()执行结束");
    }
}
@SpringBootTest
@Slf4j
@RunWith(SpringRunner.class)
public class AsyncTasksTest {
    @Resource
    private AsyncTasksService asyncTasksService;
    @Test
    public void test() throws Exception {
        long start = System.currentTimeMillis();

        CompletableFuture<String> task1 = asyncTasksService.doTaskOne();
        CompletableFuture<String> task2 = asyncTasksService.doTaskTwo();
        CompletableFuture<String> task3 = asyncTasksService.doTaskThree();

        CompletableFuture.allOf(task1, task2, task3).join();

        long end = System.currentTimeMillis();

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

 测试结果:

11:02:20.078 [task-3] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()开始
11:02:20.078 [task-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()开始
11:02:20.078 [task-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()开始
11:02:24.453 [task-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()执行结束,耗时:4375毫秒
11:02:26.571 [task-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()执行结束,耗时:6493毫秒
11:02:27.570 [task-3] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()执行结束,耗时:7492毫秒
11:02:27.571 [main] INFO  com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:7500毫秒

线程池配置

为了控制异步任务的并发不影响到应用的正常运作,我们必须要对线程池做好相应的配置,防止资源的过渡使用

Spring Boot默认用于异步任务线程池配置

源码位置:org.springframework.boot.autoconfigure.task.TaskExecutionProperties

 线程池配置

spring:
  task:
    execution:
      pool:
        core-size: 8
        max-size: 5
        queue-capacity: 10
        keep-alive: 60s
        allow-core-thread-timeout: true
      shutdown:
        await-termination: false
        await-termination-period:
      thread-name-prefix: hightask-
task:
  execution:
    pool:
      core-size: 8 (线程池创建时的初始化线程数,默认为8)
      max-size: 5 (线程池的最大线程数,默认为int最大值,即(2^31)-1)
      queue-capacity: 10 (用来缓冲执行任务的队列,默认为int最大值,即(2^31)-1)
      keep-alive: 60s  (线程终止前允许保持空闲的时间)
      allow-core-thread-timeout: true (是否允许核心线程超时)
    shutdown:
      await-termination: false (是否等待剩余任务完成后才关闭应用)
      await-termination-period: (等待剩余任务完成的最大时间)
    thread-name-prefix: hightask- (线程名的前缀)

 配置线程池,并将初始化线程数改成2后结果:

15:11:00.786 [hightask-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()开始
15:11:00.786 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()开始
15:11:02.434 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()执行结束,耗时:1648毫秒
15:11:02.434 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()开始
15:11:04.397 [hightask-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()执行结束,耗时:1963毫秒
15:11:04.757 [hightask-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()执行结束,耗时:3971毫秒
15:11:04.757 [main] INFO  com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:3979毫秒

 线程池隔离

为什么需要线程池隔离?

@Async创建的异步任务都是共用的一个线程池,当有一些异步任务碰到性能问题的时候,是会直接影响其他异步任务的。

线程池隔离实现Demo

 线程池配置:

package com.springwork.high.asyncTasks;



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 gj
 * @version 1.0.0
 * @date 2023/5/26 15:25
 */
@EnableAsync
@Configuration
public class AsyncTasksPoolConfig {
    @Bean(name = "highExecutor1")
    public Executor asyncTaskExecutor1() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("high-1-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
    @Bean(name = "highExecutor2")
    public Executor asyncTaskExecutor2() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(2);
        executor.setQueueCapacity(10);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix("high-2-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

 异步任务:

package com.springwork.high.asyncTasks;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.CompletableFuture;

/**
 * @author gj
 * @version 1.0.0
 * @date 2023/5/26 10:17
 */
@Component
@Slf4j
public class AsyncTasksService {

    public static Random random = new Random();

    @Async("highExecutor1")
    public CompletableFuture<String> doTaskOne(String taskName) throws Exception {
        log.info("开始任务:"+taskName);
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("执行结束"+taskName+"耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("doTaskOne()执行结束");
    }
    @Async("highExecutor2")
    public CompletableFuture<String> doTaskTwo(String taskName) throws Exception {
        log.info("开始任务:"+taskName);
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("执行结束"+taskName+"耗时:" + (end - start) + "毫秒");
        return CompletableFuture.completedFuture("执行结束");
    }
}

测试demo

        CompletableFuture<String> task1 = asyncTasksService.doTaskOne("1");
        CompletableFuture<String> task2 = asyncTasksService.doTaskOne("2");
        CompletableFuture<String> task3 = asyncTasksService.doTaskOne("3");
        CompletableFuture<String> task4 = asyncTasksService.doTaskTwo("4");
        CompletableFuture<String> task5 = asyncTasksService.doTaskTwo("5");
        CompletableFuture<String> task6 = asyncTasksService.doTaskTwo("6");


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

测试结果:

 15:44:50.899 [high-1-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:1
15:44:50.899 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:5
15:44:50.899 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:2
15:44:50.899 [high-2-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:4
15:44:51.159 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束2耗时:260毫秒
15:44:51.159 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:3
15:44:51.442 [high-1-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束1耗时:542毫秒
15:44:52.724 [high-1-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束3耗时:1564毫秒
15:45:00.414 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束5耗时:9515毫秒
15:45:00.414 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:6
15:45:00.690 [high-2-1] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束4耗时:9791毫秒
15:45:00.764 [pool-2-thread-1] INFO  com.springwork.high.common.ScheduleTaskCommon - CurrentTime: 2023-05-26T15:45:00.764
15:45:08.855 [high-2-2] INFO  com.springwork.high.asyncTasks.AsyncTasksService - 执行结束6耗时:8440毫秒
15:45:08.856 [main] INFO  com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:17964毫秒

参考内容:

http://t.csdn.cn/Drzb4

http://t.csdn.cn/9usjv

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/25317.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Modern CSV:大型 CSV 文件编辑器/查看器 Crack

Modern CSV用于快速查看大型 CSV 文件 适用于 Windows、Mac 和 Linux 的复杂 CSV 编辑器/查看器 被使用 电子商务运营商。数据科学家。会计师。 IT 专业人员。学生。医学研究人员。数字营销人员。生物学家。工程师。 现代 CSV 是适用于 Windows、Mac 和 Linux 的功能强大的表格…

面向对象编程 实验三 sduwh 子窗口与控件的基本用法、资源的使用 参考实验报告1

源自网络收集&#xff0c;仅供参考 实验三收集到两份完整报告&#xff0c;这是其一&#xff0c;另一份见本专栏下一篇文章。 实验题目 《面向对象程序设计》 实验三 实验题目&#xff1a;子窗口与控件的基本用法、资源的使用 整体目的&#xff1a;理解、窗口之间的消息传送…

【Netty】Netty中的超时处理与心跳机制(十九)

文章目录 前言一、超时监测二、IdleStateHandler类三、ReadTimeoutHandler类四、WriteTimeoutHandler类五、实现心跳机制5.1. 定义心跳处理器5.2. 定义 ChannelInitializer5.3. 编写服务器5.4. 测试 结语 前言 回顾Netty系列文章&#xff1a; Netty 概述&#xff08;一&#…

内存栈与CPU栈机制

1. 内存栈: 先入后出,LIFO(LAST IN FIRST OUT) 入栈:将一个新的元素放到栈顶 出栈:从栈顶取出一个元素 栈顶元素总是最后一个入栈,需要时出栈. 2.CPU栈机制 8086CPU提供相关指令以栈方式来访问内存空间.相当于将一段内存当做栈来使用 8086CPU提供的入栈指令为:PUSH ,出栈指令为…

JointJS+ v3.7 Crack

JointJS v3.7 改进了对 SVG 上下文中的外部对象的支持。 2023 年 5 月 30 日 - 16:00 新版本 特征 改进了对外部对象 (HTML) 的支持- 外部对象已成为 Web 开发的标准&#xff0c;JointJS 现在已经在 SVG 上下文中引入了对外部对象的全面且功能齐全的支持。这意味着您现在可以在…

Elasticsearch 8.8.0 发布

Elasticsearch 是一个基于 Lucene 库的搜索引擎。它提供了一个分布式、支持多租户的全文搜索引擎&#xff0c;具有 HTTP Web 接口和无模式 JSON 文档。Elasticsearch 基于 Java 开发&#xff0c;并在 SSPL Elastic License 双重授权许可下作为开源软件发布。 Elasticsearch 8…

win10系统如何设置虚拟回环

在日常生活中&#xff0c;人们(特别是IT行业者)通常需要在一台机上进行软件测试&#xff0c;而同一台计算上通常只能使用一个地址&#xff0c;而在需要同时使用两个地址进行测试的时候就显得捉襟见肘。此方法通过配置window10自带的环回适配器&#xff0c;达到上述目的。 win1…

如何使用Kali进行信息收集?

渗透测试即模拟黑客入侵的手段对目标网络进修安全测试&#xff0c;从而发现目标网络的漏洞&#xff0c;对目标网络进行安全加固与漏洞修复。 Kali 是一个基于 debian 的渗透测试平台&#xff0c;其中集成了很多常见的和不常见的渗透测试工具&#xff0c;如下图&#xff1a; 工…

基于SSM的服装设计供需系统设计与实现

摘 要&#xff1a;作为服装设计的重要形式之一&#xff0c;服装具有显著的审美性&#xff0c;是人类情感表达不可忽视的代表形态。但在新时期背景下&#xff0c;随着服装设计的进一步优化&#xff0c;服装设计创新融合强度也随之增强。本文就服装设计供需系统进行深入探究。 服…

Linux之命令搜索

目录 Linux之命令搜索 Whereis命令 定义 基本信息 举例 which命令 定义 与whereis命令的区别 基本信息 举例 locate 命令 定义 优点 缺点 基本信息 案例 Linux之命令搜索 Whereis命令 定义 whereis --- 搜索系统命令的命令&#xff08;像绕口令一样&#xff09…

数据库新闻速递 明白3中主流的数据迁移方法 (译)

头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共8…

ShardingSphere笔记(三):自定义分片算法 — 按月分表·真·自动建表

ShardingSphere笔记&#xff08;二&#xff09;&#xff1a;自定义分片算法 — 按月分表真自动建表 文章目录 ShardingSphere笔记&#xff08;二&#xff09;&#xff1a;自定义分片算法 — 按月分表真自动建表一、 前言二、 Springboot 的动态数据库三、 实现我们自己的动态数…

MySQL查询当前数据和上一行数据比较、业务数据的趋势分析、数据变动的监控和报警

标题: 使用MySQL查询当前数据和上一行数据比较的场景 在MySQL中&#xff0c;我们经常需要对数据进行比较和分析。其中一种常见的需求是查询数据列表并与前一行的数据进行比较。这种场景可以通过使用窗口函数或连接来实现。本文将介绍使用MySQL查询比较数据和上一行数据的场景&a…

计算机组成原理-指令系统-指令格式及寻址方式

目录 一、指令的定义 1.1 扩展操作码指令格式 二、指令寻址方式 2.1 顺序寻址 2.2 跳跃寻址 三、 数据寻址 3.1 直接寻址 3.2 间接寻址 3.3 寄存器寻址 ​ 3.4 寄存器间接寻址 3.5 隐含寻址 3.6 立即寻址 3.7 偏移地址 3.7.1 基址寻址 3.7.2 变址寻址 3.7.3 相对寻址…

【C++】右值引用和移动语义(详细解析)

文章目录 1.左值引用和右值引用左值引用右值引用 2.左值引用和右值引用的比较左值引用总结右值引用总结 3.右值引用的使用场景和意义知识点1知识点2知识点3知识点4总结 4.完美转发万能引用见识完美转发的使用完美转发的使用场景 1.左值引用和右值引用 传统的C语法中就有引用的…

【SpringCloud】SpringAMQP总结

文章目录 1、AMQP2、基本消息模型队列3、WorkQueue模型4、发布订阅模型5、发布订阅-Fanout Exchange6、发布订阅-DirectExchange7、发布订阅-TopicExchange8、消息转换器 1、AMQP Advanced Message Queuing Protocol&#xff0c;高级消息队列协议。是用于在应用程序之间传递业务…

Java设计模式(三)

系列文章目录 迪米特法则 合成复用原则 设计原则核心思想 文章目录 系列文章目录前言一、迪米特法则1.迪米特法则基本介绍2.迪米特法则注意事项和细节 二、合成复用原则1.合成复用原则基本介绍 三、设计原则核心思想总结 前言 大家好呀&#xff0c;欢迎来到柚子的博客~让我们…

CAPL(vTESTStudio) - CAPL、CANoe、Panel联动

目录 一、变量设置 ① dbc文件中的Environment variables变量

图灵完备游戏:信号计数 解法记录

使用1个全加器 2个半加器完成。这关的思想主旨在于如何把输出4&#xff0c;输出2&#xff0c;输出1的情况统一在一根导线上。 首先用一个全加器来完成输入2-4这三个引脚的计数&#xff0c;因为全加器输出范围二进制是00 - 11&#xff0c;而输入正好有两个引脚数位是2和1&…

高压放大器在大学教研领域的实际应用

在大学教研领域中&#xff0c;高压放大器可以用于多种实际应用。下面将介绍其中几个典型的应用场景。 1、激光切割 适用高校学院&#xff1a;机械学院 应用场景&#xff1a;机械制造、各类材料的切割 2、超声雾化 适用高校学院&#xff1a;医学院、机械学院、物理学院 应用场景…
最新文章