spring异步方法@Async

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring异步方法@Async相关的知识,希望对你有一定的参考价值。

参考技术A 在Spring Boot中,我们只需要使用@Async注解就能简单的将原来的同步函数变为异步函数。

开启方法:启动类或者配置类上加@EnableAsync注解,然后在方法或者类上加@Async,类上加注解表示类中方法都实现异步调用。

工作原理:

spring 在扫描bean的时候会扫描方法上是否包含@async的注解,如果包含的,spring会为这个bean动态的生成一个子类,我们称之为代理类,代理类是继承我们所写的bean的,然后把代理类注入进来,那此时,在执行此方法的时候,会到代理类中,代理类判断了此方法需要异步执行,就不会调用父类的对应方法。spring自己维护了一个队列,他会把需要执行的方法,放入队列中,等待线程池去读取这个队列,完成方法的执行,从而完成了异步的功能。spring提供了默认线程池ThreadPoolTaskExecutor,支持手动配置属性。

需要注意的地方:

1.在同一个类中的方法调用,添加@async注解是失效的。原因是当你在同一个类中的时候,方法调用是在类中执行的,spring无法截获这个方法调用,也就不会在代理类里执行。

2.可能会导致循环依赖,spring本身会解决循环依赖,但是因为@Async使用代理模式,spring在检查第二级缓存和原始对象是否相等时发现不相等,会抛出异常。

3.无法获取请求上下文。

Spring异步方法注解 @Async

@Async

0. 介绍

在Spring 3.x之后,通过内置@Async标明异步方法,可以简化异步开发流程。

@Async既可提供无返回值的调用,也可提供有返回值的调用,下文将分别介绍两种使用方式。

1. 代码Demo

1.1 线程池配置

Spring线程池配置有两种基本配置方式,此处实用其中一种

<task:executor id="myexecutor" pool-size="5"  />  
<task:annotation-driven executor="myexecutor"/> 

1.2 无返回值的调用方式

  • 测试类
@Component
public class AsyncTask {

    @Async
    public void exec() throws Exception{
        System.out.println("准备睡觉:" + System.currentTimeMillis());
        Thread.sleep(10);
        System.out.println("醒了");
    }
}

-测试代码

public class AsyncTaskTest extends AbstractTest {

    @Autowired
    private AsyncTask asyncTask;

    @Test
    public void testExec() throws Exception {
        for (int i= 0; i<5;i++)
            asyncTask.exec();

        Thread.sleep(1000L);
    }
}
  • 测试结果
准备睡觉:1511882628039
准备睡觉:1511882628039
准备睡觉:1511882628039
准备睡觉:1511882628039
准备睡觉:1511882628039
醒了
醒了
醒了
醒了
醒了
  • 结果分析

从代码输出来看,五个任务在同一时间被执行,说明@Async注解能够达到异步执行方法的目的。

1.3 有返回值的调用

@Async标记的方法,可返回AsyncResult结果,该类为Future子类,因此该类可通过future.get()和future.get(long timeout, TimeUnit unit)拿到返回结果;

  • 测试类
@Component
public class AsyncTask {

    @Async
    public Future<String> exec() throws Exception{
        System.out.println("准备睡觉" + System.currentTimeMillis());
        Thread.sleep(10);
        System.out.println("醒了");
        return new AsyncResult<String>("有力气了");
    }
}
  • 测试代码
public class AsyncTaskTest extends AbstractTest {

    @Autowired
    private AsyncTask asyncTask;

    @Test
    public void testExec() throws Exception {
        String asyncResult1 = asyncTask.exec().get();
        String asyncResult2 = asyncTask.exec().get();
        String asyncResult3 = asyncTask.exec().get();
        String asyncResult4 = asyncTask.exec().get(50, TimeUnit.MILLISECONDS);
        String asyncResult5 = asyncTask.exec().get(50, TimeUnit.MILLISECONDS);

        System.out.println("result1:" + asyncResult1);
        System.out.println("result2:" + asyncResult2);
        System.out.println("result3:" + asyncResult3);
        System.out.println("result4:" + asyncResult4);
        System.out.println("result5:" + asyncResult5);
    }
}

  • 测试结果
准备睡觉1511883563474
醒了
准备睡觉1511883563487
醒了
准备睡觉1511883563498
醒了
准备睡觉1511883563510
醒了
准备睡觉1511883563521
醒了
result1:有力气了
result2:有力气了
result3:有力气了
result4:有力气了
result5:有力气了
  • 结果分析

通过设置超时时,可在约定时间内获取结果,避免程序hang住,该方法较为实用。

以上是关于spring异步方法@Async的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 微服务异步调用 @EnableAsync @Async

Spring Boot中异步线程池@Async详解

Spring异步方法注解 @Async

Spring中@Async注解实现“方法”的异步调用

关于Dubbo和Spring异步注解@Async的冲突

异步任务spring @Async注解源码解析