SpringBoot中使用@Async注解实现异步调用

在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,在spring 3.x之后,spring内置了@Async来解决这个问题。

常规的异步调用处理方式

在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,通过主线程和不同的线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。

@Async介绍

在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。

要想实现异步调用
首先要在SpringBoot中的启动类中需要添加注解@EnableAsync来开启异步调用。
在需要异步执行的方法上添加@Async注解进行标注。

在使用该注解时一般会添加一个线程池的配置,不影响主线程,异步方法交给单独的线程完成

@Configuration
public class AsyncConfig {
     

    private static final int MAX_POOL_SIZE = 50;

    private static final int CORE_POOL_SIZE = 20;

    @Bean("taskExecutor")
    public AsyncTaskExecutor taskExecutor() {
     
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        taskExecutor.setThreadNamePrefix("async-task-thread-pool");
        taskExecutor.initialize();
        return taskExecutor;
    }
}
基于@Async无返回值调用
@Async("taskExecutor")  //标注使用
public void asyncMethodWithVoidReturnType() {
     
   System.out.println("异步调用" + Thread.currentThread().getName());
}
要带有返回值的Future,需要用到AsyncResult
@Async("taskExecutor")
public Future<String> asyncMethodWithReturnType() {
     
    System.out.println("线程:" + Thread.currentThread().getName());
    try {
     
        Thread.sleep(5000);
        return new AsyncResult<String>("hello world !!!!");
    } catch (InterruptedException e) {
     
        //
    }
 
    return null;
}

以上示例可以发现,返回的数据类型为Future类型,其为一个接口。具体的结果类型为AsyncResult,这个是需要注意的地方。
 
  调用返回结果的异步方法示例:

public void testAsyncAnnotationForMethodsWithReturnType()
   throws InterruptedException, ExecutionException {
     
    System.out.println("当前线程:"+ Thread.currentThread().getName());
    Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
 
    while (true) {
       ///这里使用了循环判断,等待获取结果信息
        if (future.isDone()) {
       //判断是否执行完毕
            System.out.println("异步调用结果: " + future.get());
            break;
        }
        System.out.println("Continue doing something else. ");
        Thread.sleep(1000);
    }
}

这些获取异步方法的结果信息,是通过不停的检查Future的状态来获取当前的异步方法是否执行完毕来实现的。

@Async调用中的事务处理机制

在@Async标注的方法,同时也适用了@Transactional进行了标注;在其调用数据库操作之时,将无法产生事务管理的控制,原因就在于其是基于异步处理的操作。

那该如何给这些操作添加事务管理呢?可以将需要事务管理操作的方法放置到异步方法内部,在内部被调用的方法上添加@Transactional.
例如:

方法A,使用了@Async/@Transactional来标注,但是无法产生事务控制的目的。
方法B,使用了@Async来标注,  B中调用了C、D,C和D分别使用@Transactional做了标注,则可实现事务控制的目的。

你可能感兴趣的:(springboot,多线程,spring)