Spring中使用@Async来实现异步调用
1.关于异步调用
- 同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。
- 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。
- 在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。
2.@Async的使用
开启@Async
- 使用@EnableAsync注解可以在项目中开启@Async。
具体使用@Async
有两种方式来使用,可以选择有返回值和无返回值。
- 无返回值
@Async
public void returnWithVoid() {
}
- 有返回值
@Async
public Future<String> returnWithString() {
return "hello world";
}
可以看到,这里使用@Async时没有设置参数,默认情况下,Spring使用SimpleAsyncTaskExecutor去执行这些异步方法(此执行器没有限制线程数)。我们也可以自定义线程池, 在不同的异步调用间做到资源隔离。
3.线程池的配置
一个项目不推荐配置一个线程池,这样若是某些业务出现异常时,会影响到整个项目的健壮性。故根据业务,为不同的业务配置不同参数的数据库连接池。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class ExecutorConfig {
/**
* 核心线程数:线程池创建时候初始化的线程数
*/
@Value("${async-executor.core.pool.size}")
private int asyncCorePoolSize;
/**
* 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
*/
@Value("${async-executor.max.pool.size}")
private int asyncMaxPoolSize;
/**
* 缓冲队列200:用来缓冲执行任务的队列
*/
@Value("${async-executor.queue.capacity}")
private int asyncQueueCapacity;
/**
* 允许线程的空闲时间(单位:秒):当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
*/
@Value("${async-executor.keepalive.Seconds}")
private int asyncKeepAliveSeconds;
/**
* 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
*/
@Value("${async-executor.thread.name.prefix}")
private String asyncThreadNamePrefix;
@Bean
public Executor asyncServiceExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new VisiableThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(asyncCorePoolSize);
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
threadPoolTaskExecutor.setMaxPoolSize(asyncMaxPoolSize);
threadPoolTaskExecutor.setQueueCapacity(asyncQueueCapacity);
threadPoolTaskExecutor.setKeepAliveSeconds(asyncKeepAliveSeconds);
threadPoolTaskExecutor.setThreadNamePrefix(asyncThreadNamePrefix);
//拒绝策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
我们可以 @Async(“asyncServiceExecutor”) 以这样的方式来指明线程池进行异步调用。