springboot-11- 异步任务处理

1. 异步任务的使用场景

异步任务是相对于同步任务来讲,同步任务就是顺序执行的任务,前面的任务没有执行完,后面的任务只能等待,而异步任务不同,它可以多个任务并行执行,异步任务有很多优点:
(1)减少主流程执行时间,避免主业务被长时间阻塞,提升服务器处理请求的并量
(2)避免因为一个辅助功能的处理失败而导致整个请求失败
比如,用户下单之后,可能系统会赠送一些积分之类的,赠送积分并不是主要流程,整个过程可以放到异步任务或者消息队列中去完成,异步任务还适用于处理log、发送邮件、短信等

2. springboot异步任务如何使用

  1. 启动类里面使用@EnableAsync注解开启功能,自动扫描
  2. 定义异步任务类并使用@Component标记组件被容器扫描,异步方法加上@Async,需要注意以下几点:
    * 要把异步任务封装到类里面,不能直接写到Controller
    * 增加Future 返回结果 AsyncResult(“task执行完成”);
    * 如果需要拿到结果 需要判断全部的 task.isDone()
  3. 通过注入方式,注入到controller里面
2.1 不带返回值的异步任务
  • 定义异步任务类,分别定义三个异步任务方法,方法中分别睡眠1s, 2s, 4s
package com.example.springbootdemo4.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

/**
 * 异步任务类,注意点:不能直接写到Controller里
 */
@Component
public class AsyncTask {
    
    

    /**
     * 异步任务1,     @Async把该方法标记为一个异步方法,或者把方法上的注解挪到类上面也可以!
     * @throws InterruptedException
     */
    @Async
    public void asyncTask1() throws InterruptedException {
    
    
        long begin = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("任务1耗时:" + (end-begin)) ;
    }
    @Async
    public void asyncTask2() throws InterruptedException {
    
    
        long begin = System.currentTimeMillis();
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        System.out.println("任务2耗时:" + (end-begin)) ;
    }
    @Async
    public void asyncTask3() throws InterruptedException {
    
    
        long begin = System.currentTimeMillis();
        Thread.sleep(4000);
        long end = System.currentTimeMillis();
        System.out.println("任务3耗时:" + (end-begin)) ;
    }
}
  • 在controller中调用上面定义的三个异步任务
package com.example.springbootdemo4.controller;

import com.example.springbootdemo4.service.AsyncTask;
import com.example.springbootdemo4.service.AsyncTask2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Future;

/**
 * 异步任务测试
 * 异步任务的意义在于把串行化执行的方法变成了异步执行,当所有异步方法执行完成后,
 * 后面的方法才继续执行
 */
@RestController
@RequestMapping("/api/v1")
public class AsyncTaskController {
    
    
    @Autowired
    private AsyncTask task;

    @Autowired
    private AsyncTask2 asyncTask;

    /**
     * 测试异步任务 http://localhost:8080/api/v1/async
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/async")
    public String execTask() throws InterruptedException {
    
    
        long start = System.currentTimeMillis();
        task.asyncTask1();
        task.asyncTask2();
        task.asyncTask3();
        long end = System.currentTimeMillis();
        System.out.println("总耗时:" + (end -start));
        return "success,suspend " +  (end -start) + "ms";
    }
}
  • 主启动类
package com.example.springbootdemo4;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
// @EnableScheduling注解开启定时任务
@EnableScheduling
// 开启异步任务:@EnableAsync会把一个类标记为异步类
@EnableAsync
public class Demo4Application {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(Demo4Application.class, args);
    }
}

浏览器输入http://localhost:8080/api/v1/async进行测试,发现execTask()方法执行耗时只需要3ms左右
在这里插入图片描述
这时把AsyncTask类中三个方法上的@Async注解去掉,让execTask()方法中变成同步调用,测试结果如下,可见异步任务和同步任务,在执行效率上差异还是很大的!
在这里插入图片描述

2.2 带返回值的异步任务
  • 定义一个带返回值的异步任务类AsyncTask2, @Async注解放到类上面,可以把该类的所有方法都标记为异步方法
package com.example.springbootdemo4.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
 * 1.异步任务类 ,不能直接写到Controller里
 * 2.
 */
@Component
@Async
public class AsyncTask2 {
    
    

    /**
     * 异步任务1,     @Async把该方法标记为一个异步方法,或者把方法上的注解挪到类上面也可以!
     * @throws InterruptedException
     */
//    @Async
    public Future<String> task4() throws InterruptedException {
    
    
        long begin = System.currentTimeMillis();
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        System.out.println("任务1耗时:" + (end-begin)) ;
        return new AsyncResult<>("任务4");
    }
//    @Async
    public Future<String> task5() throws InterruptedException {
    
    
        long begin = System.currentTimeMillis();
        Thread.sleep(3000);
        long end = System.currentTimeMillis();
        System.out.println("任务5耗时:" + (end-begin)) ;
        return new AsyncResult<>("任务5");
    }
//    @Async
    public Future<String> task6() throws InterruptedException {
    
    
        long begin = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("任务6耗时:" + (end-begin)) ;
        return new AsyncResult<>("任务6");
    }
}
  • controller中进行调用:在上面的controller中加入下面这个API接口,带返回值的异步任务,必须等到所有异步任务执行结束才能拿到结果
   /**
     * 带有返回值的异步任务测试
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/async2")
    public String execTask2() throws InterruptedException, ExecutionException {
    
    
        long start = System.currentTimeMillis();
        Future<String> task4 = asyncTask.task4();
        Future<String> task5 = asyncTask.task5();
        Future<String> task6 = asyncTask.task6();
        for(;;){
    
    
            if(task4.isDone() && task5.isDone() && task6.isDone()){
    
    
                // 等待异步任务分别执行结束
                break;
            }
        }
        long end = System.currentTimeMillis();
   
        System.out.println("总耗时:" + (end -start));
        return "success,suspend " +  (end -start) + "ms" + "; task4 result = " + task4.get();
    }

http://localhost:8080/api/v1/async2 测试结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_41300437/article/details/107778083
今日推荐