springboot的异步任务:无返回值和有返回值问题
作者: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左右,而不是最慢的那个任务的时间
}
}总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
