栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot异步任务记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot异步任务记录

简介

突发奇想,就想玩一下异步任务,记得之前项目有个场景需要使用异步执行,但是异步调用没有成功,后来采用了多线程去执行,今天就系统的学习下异步执行任务。记录一下

有时候在项目中,当访问其他人的接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行, 我们可以使用多线程来并行的处理任务,也可以使用 spring 提供的异步处理方式 @Async 。

在异步处理的方法上添加注解 @Async ,就会启动一个新的线程去执行。

  1. Spring 通过任务执行器 TaskExecutor ,来实现多线程和并发编程,使用 ThreadPoolTaskExecutor 可实现一个基于线程池的 TaskExecutor ;

  2. 异步需要在配置类上面加 @EnableAsync  来开启对异步任务的支持在需要异步执行的方法上面加 @Async  来声明这个方法是一个需要异步执行的方法;

  3. 让配置类实现 AsyncConfigurer 接口,并重写 getAsyncExecutor 方法,并返回一个 ThreasPoolTaskExecutor ,就可以获取一个基于线程池的 TaskExecutor ;

  4. @Async 用在方法上,表示这个方法是一个异步的方法,如果用在类上面,表明这个类中的所有方法都是异步的方法。

测试
  • 新建 SpringBoot 项目,导入如下依赖


    org.springframework.boot
    spring-boot-starter-parent
    2.5.3
     



    
        org.springframework.boot
        spring-boot-starter-web
    
    
        org.projectlombok
        lombok
        true
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
  • 创建一个配置类,配置线程池参数
package com.mobaijun.config;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;


@Configuration
@EnableAsync // @EnableAsync:通过在配置类或者启动(Main)类上加@EnableAsync开启对异步方法的支持。
public class TaskExecutorConfig implements AsyncConfigurer {

    

    
    private static final int CORE_POOL_SIZE = 5;

    
    private static final int MAX_POOL_SIZE = 20;

    
    private static final int QUEUE_CAPACITY = 10;
    
    private static final String THREAD_NAME_PREFIX = "task—";

    
    @Bean
    public Executor getAsyncExecutor() {
        // 1.Spring 默认配置是核心线程数大小为1,最大线程容量大小不受限制,队列容量也不受限制。
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 2.核心线程数
        taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        // 3.最大线程数
        taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        // 4.队列大小
        taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
        // 5.线程前缀名称
        taskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);
        // 6.当最大池已满时,此策略保证不会丢失任务请求,但是可能会影响应用程序整体性能。
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 7.初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }

    
    @Bean
    public Executor getMineAsync() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(CORE_POOL_SIZE - 4);
        executor.setMaxPoolSize(MAX_POOL_SIZE - 10);
        executor.setQueueCapacity(QUEUE_CAPACITY - 5);
        executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}
  • 编写一个伪实现类
package com.mobaijun.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.concurrent.Future;


@Slf4j
@Component
public class ArithmeticService implements Serializable {

    
    public static final int DoTime = 5000;

    
    @Async
    public Future subByAsync() throws Exception {
        long start = System.currentTimeMillis();
        long sum = 0;
        Thread.sleep(DoTime);
        long end = System.currentTimeMillis();
        sum = end - start;
        log.info("t 完成任务一");
        return new AsyncResult<>(sum);
    }

    
    @Async
    public void subByVoid() throws Exception {
        long start = System.currentTimeMillis();
        long sum = 0;
        Thread.sleep(DoTime);
        long end = System.currentTimeMillis();
        sum = end - start;
        log.info("t 完成任务二   ");
        log.info("注解任务执行的时间是: " + sum + "(毫秒)");
    }

    
    public long subBySync() throws Exception {
        long start = System.currentTimeMillis();
        long sum = 0;
        Thread.sleep(DoTime);
        long end = System.currentTimeMillis();
        sum = end - start;
        log.info("t 完成任务三   ");
        return sum;
    }

    @Async("getMineAsync")
    public void doMineAsync(int i) throws Exception {
        System.out.println("------t:" + i);
        Thread.sleep(10000);
    }
}
  • web接口
package com.mobaijun.controller;

import com.mobaijun.service.ArithmeticService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Future;


@Slf4j
@RestController
public class AsyncController {

    @Autowired
    private ArithmeticService arithmeticService;

    @SuppressWarnings("static-access")
    @RequestMapping(value = {"/"}, method = RequestMethod.GET)
    public void index() {
        long start = System.currentTimeMillis();
        try {
            log.info("--------------------------------------------n");
            log.info("每个任务执行的时间是:" + arithmeticService.DoTime + "(毫秒)");
            Future task = arithmeticService.subByAsync();
            arithmeticService.subByVoid();
            long sync = arithmeticService.subBySync();
            while (true) {
                if (task.isDone()) {
                    long async = task.get();
                    log.info("异步任务执行的时间是:" + async + "(毫秒)");
                    // log.info("注解任务执行的时间是: -- (毫秒)");
                    log.info("同步任务执行的时间是:" + sync + "(毫秒)");
                    break;
                }
            }
            log.info("--------------------------------------------n");
        } catch (Exception e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        log.info("t........请求响应时间为:" + (end - start) + "(毫秒)");
    }

    
    @RequestMapping(value = {"/mine", "/m*"}, method = RequestMethod.GET)
    public void mineAsync() {
        for (int i = 0; i < 100; i++) {
            try {
                arithmeticService.doMineAsync(i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
  • 接口一请求结果:http://localhost:8004/
2021-08-02 17:23:45.047  INFO 14376 --- [nio-8004-exec-1] com.mobaijun.controller.AsyncController  : 每个任务执行的时间是:5000(毫秒)
2021-08-02 17:23:50.068  INFO 14376 --- [  thread-exec-1] com.mobaijun.service.ArithmeticService   :     完成任务一
2021-08-02 17:23:50.068  INFO 14376 --- [  thread-exec-2] com.mobaijun.service.ArithmeticService   :     完成任务二   
2021-08-02 17:23:50.068  INFO 14376 --- [nio-8004-exec-1] com.mobaijun.service.ArithmeticService   :     完成任务三   
2021-08-02 17:23:50.068  INFO 14376 --- [  thread-exec-2] com.mobaijun.service.ArithmeticService   : 注解任务执行的时间是: 5014(毫秒)
2021-08-02 17:23:50.068  INFO 14376 --- [nio-8004-exec-1] com.mobaijun.controller.AsyncController  : 异步任务执行的时间是:5014(毫秒)
2021-08-02 17:23:50.068  INFO 14376 --- [nio-8004-exec-1] com.mobaijun.controller.AsyncController  : 同步任务执行的时间是:5014(毫秒)
2021-08-02 17:23:50.069  INFO 14376 --- [nio-8004-exec-1] com.mobaijun.controller.AsyncController  : --------------------------------------------
  • 接口二请求结果,截取部分内容:http://localhost:8004/mine
------  :0
------  :6
------  :7
------  :8
------  :9
------  :10
------  :11
------  :12
------  :15
------  :13
------  :14

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/927312.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号