我有一个使用CommandLineRunner
和Spring @Async
批注来异步运行方法的Spring Boot应用程序。一切正常,但是当我所有的线程完成时,应用程序只是挂起而不是退出。
这是我的应用程序中的一个最小示例:
Application.java :
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ApplicationStartup.java :
@Component
public class ApplicationStartup implements CommandLineRunner {
private final AsyncService asyncService;
@Inject
public ApplicationStartup(final AsyncService asyncService) {
this.asyncService = asyncService;
}
@Override
public void run(final String... strings) throws Exception {
//my logic is more complicated than this, but this illustrates my point
for (int i = 0; i < 1000; i++) {
asyncService.runAsyncMethod();
}
}
}
AsyncService.java :
@Service
@Transactional
public class AsyncService {
@Async
public void runAsyncMethod() {
//perform call to an API and process results
}
}
ExecutorConfig.java :
@Configuration
public class ExecutorConfig() {
@Bean
public ThreadPoolTaskExecutor asyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(64);
executor.setMaxPoolSize(64);
executor.setQueueCapacity(500);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("Scrub-");
executor.setKeepAliveSeconds(60);
executor.initialize();
return executor;
}
}
我所有的线程都对
runAsyncMethod()
进行了调用,并且每个方法调用均成功完成,但是应用程序只是挂起了。我尝试更改一些执行程序设置。一开始我没有
keepAliveSeconds
,所以我想添加它就可以解决它,但是在所有线程完成后它仍然挂起。我将corePoolSize
更改为0
,这使应用程序在完成时退出,但整个过程仅使用1个线程。关于为什么应用程序没有退出上述配置的任何想法?
最佳答案
您错过了加入异步作业的原因,这就是run
方法在所有线程完成之前(远)退出的原因-尴尬的行为“更容易理解”。
根据doc,您可以像这样加入:
...
CompletableFuture<Void>[] myJobs = new CompletableFuture<>[N];
...
for (int i = 0; i < N; i++) {
myJobs[i] = asyncService.runAsyncMethod();
}
...
CompletableFuture.allOf(myJobs).join();
并且您的
runAsyncMethod()
将需要返回CompletableFuture<Void>
。为此,您可以return CompletableFuture.completedFuture(null);