springboot异步任务

1、概述

在开发中,我们一般是同步调用,在一些和主线程关联度较低的逻辑,我们可以使用异步调用。例如说:记录用户访问日志到数据库。

Spring FrameworkSpring Task 模块,提供了 @Async注解,可以添加在方法上,自动实现该方法的异步调用。

2、简单使用

2.1、引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2.2、启用异步功能

@EnableAsync
public class Springboot02Application {

    public static void main(String[] args) {
        SpringApplication.run(Springboot02Application.class, args);
    }

}

2.3、DemoService

@Slf4j
@Service
public class DemoService {

    @Async //异步
    public Integer servic1() {
        log.info("[servic1]");
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return 1;
    }

    @Async
    public Integer servic2() {
        log.info("[servic2]");
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return 2;
    }
}

@Async注解

2.4、单元测试

@Slf4j
@SpringBootTest(classes = Springboot02Application.class)
class DemoServiceTest {

    @Autowired
    private DemoService demoService;

    @Test
    public void task01() {
        long now = System.currentTimeMillis();
        log.info("[task01][开始执行]");

        demoService.servic1();
        demoService.servic2();

        log.info("[task01][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cYcszpKg-1599469717471)(images/image-20200907162452080.png)]

2.5、等待异步调用结果

改造DemoService

@Slf4j
@Service
public class DemoService {

    public Integer servic1() {
        log.info("[servic1]");
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return 1;
    }

    @Async
    public Future<Integer> servic1AsyncWithFuture() {
        return AsyncResult.forValue(this.servic1());

    }
    
    public Integer servic2() {
        log.info("[servic2]");
        try {
            Thread.sleep(5 * 1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return 2;
    }

    @Async
    public Future<Integer> servic2AsyncWithFuture() {
        return AsyncResult.forValue(this.servic2());

    }
}
//DemoServiceTest.java
   @Test
    public void task02() throws ExecutionException, InterruptedException{
        long now = System.currentTimeMillis();
        log.info("[task01][开始执行]");
        Future<Integer> integerFuture = demoService.servic1AsyncWithFuture();
        Future<Integer> integerFuture1 = demoService.servic2AsyncWithFuture();
        integerFuture.get();
        integerFuture1.get();

        log.info("[task01][结束执行,消耗时长 {} 毫秒]", System.currentTimeMillis() - now);
    }

在这里插入图片描述

2.6、配置ThreadPoolTaskExecutor

手动配置,如:

@Configuration
public class ExecutorConfig
{

    @Bean
    public TaskExecutor taskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(5);
        // 设置最大线程数
        executor.setMaxPoolSize(10);
        // 设置队列容量
        executor.setQueueCapacity(20);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("pool-");
        // 设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        return executor;
    }
}

@Async("taskExecutor")
public void test1(){
    log.info("hello world")
}

自动配置

application.yml中,添加 Spring Task的配置,如下:

spring:
  task:
    # Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
    execution:
      thread-name-prefix: task- # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
      pool: # 线程池相关
        core-size: 8 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
        max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
        keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
        queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
        allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
      shutdown:
        await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
        await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置
  • spring.task.execution 配置项,Spring Task 调度任务的配置,对应 TaskExecutionProperties]配置类。
  • Spring Boot TaskExecutionAutoConfiguration自动化配置类,实现 Spring Task 的自动配置,创建 ThreadPoolTaskExecutor基于线程池的任务执行器。本质上,ThreadPoolTaskExecutor 是基于 ThreadPoolExecutor 的封装,主要增加提交任务,返回 ListenableFuture 对象的功能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值