SpringBoot之@Async——轻松开启异步任务

异步任务

在很多业务中我们需要考虑到异步执行某些任务,特别时耗时较长的http接口的调用,
例如:

  • 短信发送:在我们调用第三方提供的短信发送接口后一般会实时收到一个响应结果,但是这个结果并不代表短信成功发送,只是表示了第三方接口校验了基本的数据没有问题后告知已收到你的短信发送请求。至于真正的短信发送流程则是异步处理。
  • 支付接口:一般的支付类接口都是异步执行转账操作,然后再去通知调用方
  • 大数据量的表格下载:一般较大数据量的表格导出会因为数据太多、sql复杂等等原因导致耗时较长,如用户在页面等待则有可能出现超时。因此许多导出都采用创建任务的形式,异步生成报表然后去下载中心下载已生成好的报表。

当然还有太多的场景就不一一列举。

创建新的线程

可能有很多兄弟现在还在通过 继承Thread 或者实现Runnable来实现新建一个线程去做异步任务,有些兄弟用上了线程池Executors.newFixedThreadPool();,而我比较懒不想去写那么多东西,我不喜欢造轮子于是我使用了@Async。

@Async简介

  • @Async在方法上使用前必须先通过@EnableAsync注册开启异步调用功能。 (当然也可以通过xml配置开启这里不做介绍)
  • 在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。
  • 在异步的方法上面,标注上 @Async 注解即表示该方法是异步运行的。不过需要注意,该方法必须是 public 的,而且,在自身类中,调用异步方法是无效的。

简单使用@Async

无返回值的异步任务

新建service用于执行异步任务

package com.zhibo.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

@EnableAsync
@Service
@Slf4j
public class AsyncDemoService {
    @Async
    public void AsyncTest1(int num) {
        log.info("----------AsyncTest1 num:{} ",num);
    }

    @Async
    public void AsyncTest2(int num){
        log.info("----------AsyncTest2 num:{} ",num);
    }

	// 有返回值的复杂异步任务
    @Async
    public Future<String> AsyncTest(int num)throws Exception{
        log.info("----------AsyncTest1 num:{} ",num);
        Thread.sleep(2000);
        return new AsyncResult<String>("Rsp AsyncTest num:"+num);
    }

	// 错误案例,同一个类中调用是同步的
    public void AsyncTestX(int num) throws Exception{
        AsyncTest1(num);
        AsyncTest2(num);
    }
}

测试用例

	@Autowired
    private AsyncDemoService asyncDemoService;

    @Test
    public void asyncTest() throws Exception{
        for (int i = 0 ; i<5;i++){
            asyncDemoService.AsyncTest1(i);
            asyncDemoService.AsyncTest2(i);
        }
        log.info("asyncTest success");
    }

输出日志

[INFO ] [zhibo-test] 2019-04-18 16:33:22.967 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - asyncTest success
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-1] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:0 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-6] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest2 num:2 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-9] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:4 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-8] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest2 num:3 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-3] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:1 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-10] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest2 num:4 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-5] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:2 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-2] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest2 num:0 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-7] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:3 
[INFO ] [zhibo-test] 2019-04-18 16:33:22.975 [SimpleAsyncTaskExecutor-4] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest2 num:1 

@Async就是这么简单任性,我承认我比较懒,但是懒惰是程序猿的美德之一!

有返回值的多线程异步任务

测试用例

	@Autowired
    private AsyncDemoService asyncDemoService;

    @Test
    public void asyncTest() throws Exception{
        //用于收集每个线程的Future
        List<Future<String>> resultList = new ArrayList<>();
        for (int i = 0 ; i<5;i++){
            Future<String> future = asyncDemoService.AsyncTest(i);
            resultList.add(future);
        }
        //开始处理返回值
        for (Future<String> future:resultList){
            //get方法是阻塞式的
            log.info(future.get());
        }
        log.info("asyncTest success");
    }

输出日志

[INFO ] [zhibo-test] 2019-04-18 20:06:56.547 [SimpleAsyncTaskExecutor-5] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:4 
[INFO ] [zhibo-test] 2019-04-18 20:06:56.547 [SimpleAsyncTaskExecutor-2] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:1 
[INFO ] [zhibo-test] 2019-04-18 20:06:56.547 [SimpleAsyncTaskExecutor-4] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:3 
[INFO ] [zhibo-test] 2019-04-18 20:06:56.547 [SimpleAsyncTaskExecutor-3] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:2 
[INFO ] [zhibo-test] 2019-04-18 20:06:56.547 [SimpleAsyncTaskExecutor-1] [] [] [] com.zhibo.service.AsyncDemoService - ----------AsyncTest1 num:0 
[INFO ] [zhibo-test] 2019-04-18 20:06:59.540 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - Rsp AsyncTest num:0
[INFO ] [zhibo-test] 2019-04-18 20:06:59.540 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - Rsp AsyncTest num:1
[INFO ] [zhibo-test] 2019-04-18 20:06:59.541 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - Rsp AsyncTest num:2
[INFO ] [zhibo-test] 2019-04-18 20:06:59.541 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - Rsp AsyncTest num:3
[INFO ] [zhibo-test] 2019-04-18 20:06:59.541 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - Rsp AsyncTest num:4
[INFO ] [zhibo-test] 2019-04-18 20:06:59.541 [main] [] [] [] com.zhibo.test.service.AsyncDemoServiceTest - asyncTest success

done~ 依然简洁。兄弟们撸起袖子加油干。
题外话:感觉现在是不是行业比几年前更不好混了?有朋友在武汉找工作异常不顺利,相比北上广深杭要自降三分之一?并且都是面试造飞机,入职拧螺丝…
听说还有面试官问百万级并发如何处理业务,可能是我太菜了我觉得这个面试问题有BUG!
1、没有描述具体的业务场景如何设计?
2、并发是什么?是不是指每秒的请求数?一秒钟百万级 要想保证响应速度的话 服务器要多少台?这种问题问一个工作三四年的不太好吧,
我因为工作原因一直没有办法接触高并发这一块不是特别了解 如果有大神愿意科普下不胜感激!谢谢

发布了18 篇原创文章 · 获赞 45 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/zhibo_lv/article/details/89387317
今日推荐