springboot的异步任务:无返回值和有返回值问题

 更新时间:2023年07月20日 09:33:49   作者:kailly235  
这篇文章主要介绍了springboot的异步任务:无返回值和有返回值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

springboot异步任务:无返回值和有返回值

在想要异步执行的方法上加上@Async注解,在controller上加上@EnableAsync,即可。

注:这里的异步方法,只能在本类之外调用,在本类调用是无效的。

无返回值的异步任务

service实现部分:

@Service
public class AsyncService {
    @Async //想要异步执行的方法上加@Async 注解
    public void doNoReturn(){
        try {
            // 这个方法执行需要三秒
            Thread.sleep(3000);
            System.out.println("方法执行结束" + new Date());
        } catch (InterruptedException e) {
            e.printStackTrace();
    }
}

controller调用部分:

@RestController
@EnableAsync//调用异步任务的controller上加@EnableAsync注解
public class AsyncController {
    @Autowired
    private AsyncService asyncService;
    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String testAsyncNoRetrun(){
        long start = System.currentTimeMillis();
         asyncService.doNoReturn();
         return String.format("任务执行成功,耗时{%s}", System.currentTimeMillis() - start);
    }

输出:

任务执行成功,耗时{4}

可见testAsyncNoRetrun()方法中 调用doNoReturn(),没等doNoReturn()执行完即返回。

有返回值的异步任务

有返回值的异步任务方法需要用Futrue变量把返回值封装起来。

service实现部分:

@Async
 public Future<String> doReturn(int i){
        try {
            // 这个方法需要调用500毫秒
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 消息汇总
        return new AsyncResult<>(String.format("这个是第{%s}个异步调用的证书", i));
}

读取的时候要批量读取不能单独读取。

controller调用部分:

@GetMapping("/hi")
    public Map<String, Object> testAsyncReturn() throws ExecutionException, InterruptedException {
        long start = System.currentTimeMillis();
        Map<String, Object> map = new HashMap<>();
        List<Future<String>> futures = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Future<String> future = asyncService.doReturn(i);
            futures.add(future);
        }
        List<String> response = new ArrayList<>();
        for (Future future : futures) {
            String string = (String) future.get();
            response.add(string);
        }
        map.put("data", response);
        map.put("消耗时间", String.format("任务执行成功,耗时{%s}毫秒", System.currentTimeMillis() - start));
        return map;
}

在浏览器输入地址:http://localhost:8080/hi

结果如下: 耗时500多毫秒的意思代表,springboot自带异步任务线程池是小于10的大小的

{"data":["这个是第{0}个异步调用的证书","这个是第{1}个异步调用的证书","这个是第{2}个异步调用的证书","这个是第{3}个异步调用的证书","这个是第{4}个异步调用的证书","这个是第{5}个异步调用的证书","这个是第{6}个异步调用的证书","这个是第{7}个异步调用的证书","这个是第{8}个异步调用的证书","这个是第{9}个异步调用的证书"],"消耗时间":"任务执行成功,耗时{508}毫秒"}

springboot的异步任务(带返回值和不带返回值的处理)

注意:在用异步任务之前先给启动类加@EnableAsync这个注解

新建异步任务包和在包里面建异步任务类

As.java异步类

package com.example.demo.async;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.concurrent.Future;
//注意:1、要把异步任务写进一个类里面而不能直接写在controller中
//      2、如果需要拿到结果,则需要在调用处判断全部的task.isDone()来确定异步任务的完成
@Component
//异步类注解,表明整个类的方法都是异步方法,如果把这个注解加在某一个方法上而不是某一个类则表明仅仅是这个方法才是异步方法
@Async
public class As {
    //下面是3个异步任务(不带返回值的)
    public void task1() throws InterruptedException {
        long begin=System.currentTimeMillis();
        Thread.sleep(3000l);
        long end=System.currentTimeMillis();
        System.out.println("任务1耗时"+(end-begin));
    }
    public void task2() throws InterruptedException {
        long begin=System.currentTimeMillis();
        Thread.sleep(2000l);
        long end=System.currentTimeMillis();
        System.out.println("任务2耗时"+(end-begin));
    }
    public void task3() throws InterruptedException {
        long begin=System.currentTimeMillis();
        Thread.sleep(1000l);
        long end=System.currentTimeMillis();
        System.out.println("任务3耗时"+(end-begin));
    }
    //下面是3个异步任务(带返回值的,可以在调用出取地返回值)
    public Future<String> task4() throws InterruptedException {
        long begin=System.currentTimeMillis();
        Thread.sleep(3000l);
        long end=System.currentTimeMillis();
        return new AsyncResult<String>("任务4耗时"+(end-begin));
    }
    public Future<String> task5() throws InterruptedException {
        long begin=System.currentTimeMillis();
        Thread.sleep(2000l);
        long end=System.currentTimeMillis();
        return new AsyncResult<String>("任务5耗时"+(end-begin));
    }
    public Future<String> task6() throws InterruptedException {
        long begin=System.currentTimeMillis();
        Thread.sleep(1000l);
        long end=System.currentTimeMillis();
        return new AsyncResult<String>("任务6耗时"+(end-begin));
    }
}

controller测试控制器

package com.example.demo.controller;
import com.example.demo.async.As;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RestController
public class He {
	//注入异步类
    @Autowired
    private As as;
    //测试异步任务没带返回值的,直接主线程瞬间就通过了
    @RequestMapping("/as")
    public Object as() throws InterruptedException {
        long begin=System.currentTimeMillis();
        as.task1();
        as.task2();
        as.task3();
        long end=System.currentTimeMillis();
        return "总耗时+"+(end-begin);
    }
    //测试异步任务带返回值的,总耗时是最慢的那个任务的耗时
    @RequestMapping("/asHava")
    public Object ash() throws InterruptedException, ExecutionException {
        long begin=System.currentTimeMillis();
        Future<String> task4=as.task4();
        Future<String> task5=as.task5();
        Future<String> task6=as.task6();
        //先小堵塞主线程一会,用以拿到异步任务返回值
        while (!(task4.isDone()&&task5.isDone()&&task6.isDone())){
        }
        long end=System.currentTimeMillis();
        //取得异步任务的返回值并查看总耗时
        return "总耗时+"+(end-begin)+"   task4结果:"+task4.get()+"  task5结果:"+task5.get()+"  task6结果:"+task6.get();
        //结果是3s左右,因为进入接口,三个异步任务瞬间开启,再瞬间到while这儿堵起
        //由于三个异步任务几乎是同时开启的,所以等最慢的那个异步任务完成以后,肯定所有的异步任务都完成了
        //所以while这时才都为true,那么放开while,所以结果就是最慢的那个异步任务的时间
        //如果说不用这种异步取值而用同步的话,那么时间就是1+2+3就是6s左右,而不是最慢的那个任务的时间
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java EasyExcel面向Excel文档读写逻辑示例详解

    java EasyExcel面向Excel文档读写逻辑示例详解

    这篇文章主要为大家介绍了java EasyExcel面向Excel文档读写逻辑示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • Java8如何从一个Stream中过滤null值

    Java8如何从一个Stream中过滤null值

    这篇文章主要介绍了Java8如何从一个Stream中过滤null值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-05-05
  • IDEA中print("")输出中文乱码的解决方式

    IDEA中print("")输出中文乱码的解决方式

    文章描述了在Java中使用System.out.print输出中文时出现乱码的问题,并提供了解决方案:修改项目的编码设置从GBK到UTF-8
    2025-10-10
  • Mybatis中Collection集合标签的使用详解

    Mybatis中Collection集合标签的使用详解

    这篇文章主要介绍了Mybatis中Collection集合标签的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java中Jackson快速入门

    Java中Jackson快速入门

    这篇文章主要介绍了Java中Jackson快速入门,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 快速解决springboot在yml配置了启动端口但启动还是8080问题

    快速解决springboot在yml配置了启动端口但启动还是8080问题

    这篇文章主要介绍了快速解决springboot在yml配置了启动端口但启动还是8080问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-03-03
  • java使用jaxb操作xml示例

    java使用jaxb操作xml示例

    JAXB主要用来实现对象和XML之间的序列化和反序列化,关于JAXB的介绍就不多说了,这里主要总结下基本使用方法和一些注意事项
    2014-04-04
  • java显示目录文件列表和删除目录功能

    java显示目录文件列表和删除目录功能

    这篇文章主要介绍了java显示目录文件列表和删除目录功能,文章通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2017-12-12
  • ShardingSphere数据分片算法及测试实战

    ShardingSphere数据分片算法及测试实战

    这篇文章主要为大家介绍了ShardingSphere数据分片算法及测试实战示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • springboot 打包部署 共享依赖包(分布式开发集中式部署微服务)

    springboot 打包部署 共享依赖包(分布式开发集中式部署微服务)

    这篇文章主要介绍了springboot 打包部署 共享依赖包(分布式开发集中式部署微服务)的相关资料,非常不错,具有参考借鉴价值,需要的的朋友参考下吧
    2017-06-06

最新评论