异步任务:适用于发送短信、邮件、处理Log等问题
比如淘宝下单接口时,我们需要查库存 150ms,余额校验 100ms,风控用户 110ms这三个,每个操作都需要调很多接口,那么花费的时间就会很长,这样用户体验会很差。如果使用了异步任务,那么就这三个操作会同时执行,是开了三个线程,不影响主线程的执行,主线程执行完会直接返回结果。如果异步任务有返回结果,那么就会取耗时最多的那个结果返回。
实战操作:
1.启动类加上@EnableAsync开启异步任务
(一)、编写三个异步没有返回值的任务
2.定义异步任务类并使用@Component标记组件被容器扫描,异步方法加上@Async或类上@Async
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;
@Component
@Async //异步类 (注意去掉注解就是同步)
public class TestAsync {
public void tack1() throws InterruptedException {
long start =System.currentTimeMillis();
Thread.sleep(1000);
long end =System.currentTimeMillis();
System.out.println("[ " + "任务1耗时 : " + (end - start) + " ]");
}
public void tack2() throws InterruptedException {
long start =System.currentTimeMillis();
Thread.sleep(2000);
long end =System.currentTimeMillis();
System.out.println("[ " + "任务2耗时 : " + (end - start) + " ]");
}
public void tack3() throws InterruptedException {
long start =System.currentTimeMillis();
Thread.sleep(3000);
long end =System.currentTimeMillis();
System.out.println("[ " + "任务3耗时 : " + (end - start) + " ]");
}
}
3.通过注入方式,注入到controller里面.
@RestController
@RequestMapping("/async/my")
public class AsyncController {
/**
* 注入异步类
*/
@Autowired
private TestAsync template;
@GetMapping("task")
public Object task() throws InterruptedException {
//开始时间
long begin = System.currentTimeMillis();
//调用方法
template.tack1();
template.tack2();
template.tack3();
//结束时间
long end = System.currentTimeMillis();
System.out.println("[ " + "Controller总耗时 : " + (end - begin) + " ]");
return JsonData.buildSuccess();
}
启动:
总之 : 主线程耗时2ms就执行完了,如果异步任务没有返回值,主线程没有等异步任务执行完就直接返回了,这样用户体验就非常好了。
(二)、编写三个异步有返回值的任务
2. 有返回值的任务返回结果是框架提供的Future<>,是java.util.concurrent.Future并发包下
获取任务的执行结果
public Future<String> tack4() throws InterruptedException {
long start =System.currentTimeMillis();
Thread.sleep(1000);
long end =System.currentTimeMillis();
System.out.println("[ " + "任务4耗时 : " + (end - start) + " ]");
//返回结果
return new AsyncResult<>("任务4");
}
public Future<String> tack5() throws InterruptedException {
long start =System.currentTimeMillis();
Thread.sleep(2000);
long end =System.currentTimeMillis();
System.out.println("[ " + "任务5耗时 : " + (end - start) + " ]");
//返回结果
return new AsyncResult<>("任务5");
}
public Future<String> tack6() throws InterruptedException {
long start =System.currentTimeMillis();
Thread.sleep(3000);
long end =System.currentTimeMillis();
System.out.println("[ " + "任务6耗时 : " + (end - start) + " ]");
//返回结果
return new AsyncResult<>("任务6");
}
3.通过注入方式,注入到controller里面.
@GetMapping("task2")
public Object task2() throws InterruptedException {
//开始时间
long begin = System.currentTimeMillis();
//调用方法
Future<String> t5= template.tack4();
Future<String> t6= template.tack5();
Future<String> t7= template.tack6();
//循环
for (;;){
if(t5.isDone() && t6.isDone() && t7.isDone()){
break;
}
}
//结束时间
long end = System.currentTimeMillis();
long total =(end - begin);
System.out.println("[ " + "Controller总耗时 : " + total + " ]");
return JsonData.buildSuccess(total);
}
启动:
总之: 耗时一共3016毫秒,它要等最迟的一个任务结束返回,如果是不需要返回结果的话几毫秒就结束了。
如果测试前后区别则改为同步则把Async注释掉
发现同步时,时间耗时很长6秒多哦!