SpringBoot之@Async实现异步

先说一下个人的理解吧:
若一个主方法需要三个子方法才能完成
同步:一个子方法执行完,才能继续执行下一个子方法;
异步:主方法里面可以同时执行三个子方法,主方法先去执行一些其他的任务,而让子方法慢慢执行,所以最后主方法可以很快执行完毕,而子线程时间就可以不用去理会。
举例:生成配送单时给司机发送短信,可以等到短信所需内容已经准备完毕时,就异步去发短信,而配送单继续向下执行。

先来看下正常用同步方法执行:

@RestController
public class AsyncTaskController {
    @Autowired
    private AsyncTask asyncTask;
    @GetMapping("/world")
    public String doTask() throws InterruptedException{
        long start = System.currentTimeMillis();
        asyncTask.task1();
        asyncTask.task2();
        asyncTask.task3();
        long end = System.currentTimeMillis();
        System.out.println("任务总耗时:" + (end - start));
        return "task任务总耗时:"+(end-start)+"ms";
    }
}
@Component
public class AsyncTask {
    public void task1() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
		Thread.sleep(1000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }

    public void task2() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(2000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }

    public void task3() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(3000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
}

控制台输出:
在这里插入图片描述
也就说明在同步的情况下,整个dotask()想要执行完就只能等每一个子方法都执行完毕,耗时为三个任务的总和。
那异步是怎么实现的呢?
首先在SpringBoot启动类,增加注解@EnableAsync
在这里插入图片描述
doTask()方法体不变,而在每一个子方法上添加注解@Async

@Component
public class AsyncTask {
    @Async
    public void task1() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
		Thread.sleep(1000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
	@Async
    public void task2() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(2000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
	@Async
    public void task3() throws InterruptedException{
        long currentTimeMillis = System.currentTimeMillis();
        Thread.sleep(3000);
        long currentTimeMillis1 = System.currentTimeMillis();
        System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
    }
}

控制台输出:
在这里插入图片描述
也就说明主方法可以很快执行完毕,而且子方法可以在多线程中慢慢执行。

总结

在启动类添加@EnableAsync时,该注解下有一个默认模式是AdviceMode.PROXY,也就是该模式会走代理。
在这里插入图片描述
Spring在扫描Bean的时候会扫描方法上是否包含@Async注解,如果包含,Spring会为这个Bean动态地生成一个子类(即代理类,proxy),代理类是继承原来那个Bean的。此时当有这个注解被调用的时候,实际上是由代理类来调用,代理类在调用的过程中增加了异步做用。

踩坑

异步方法一定不能和调用方法放在同一个类里面,否则将执行的是同步线程。
查看官方API可知:同一个类中的本地调用不能以这种方式被截获;
在这里插入图片描述
原因参考:
https://blog.csdn.net/clementad/article/details/47339519
参考博文:
https://blog.csdn.net/v2sking/article/details/72795742#

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页