I have an executor,
@Bean("someExecutor")
public Executor someExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("AsyncMethod-");
executor.initialize();
return executor;
}
and a async method.
@Async("someExecutor")
public Future<List<String>> someMethod(){
return CompletableFuture.supplyAsync(() -> {
//long time job
return listGeneratedByLongTimeJob;
});
}
Will Spring use the someExecutor for someMethod? And how?
I know an overloading method for supplyAsync(supplier) is supplyAsync(supplier, executor), how about the following code?
@Autowired("someExecutor")
private Executor executor;
@Async()
public Future<List<String>> someMethod(){
return CompletableFuture.supplyAsync(() -> {
//long time job
return listGeneratedByLongTimeJob;
}, executor);
}
Thanks.
Okay this taken while to figure this out, and before going to two scenarios we need to discuss about ForkJoinPool
from java.util.concurrent.CompletableFuture docs
All async methods without an explicit Executor argument are performed using the ForkJoinPool.commonPool() (unless it does not support a parallelism level of at least two, in which case, a new Thread is created to run each task). To simplify monitoring, debugging, and tracking, all generated asynchronous tasks are instances of the marker interface CompletableFuture.AsynchronousCompletionTask.
So when every you are calling CompletableFuture.supplyAsync(Supplier s), supplier will be executed by ForkJoinPool thread, now lets start case 1
Case 1:
To make it clear i have added some sysout statements to print thread names
@Async("someExecutor")
public Future<String> asyncService() {
System.out.println();
System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());
System.out.println();
return CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());
return "hello";
});
}
Output:
AsyncMethod-1 - java.lang.ThreadGroup[name=main,maxpri=10]
ForkJoinPool.commonPool-worker-1 - java.lang.ThreadGroup[name=main,maxpri=10]
In this case asyncService() is executed by AsyncMethod-1 thread and,
supplier in supplyAsync() is executed by ForkJoinPool
case 2:
@Autowired
private Executor someExecutor;
@Async
public Future<String> asyncService() {
System.out.println();
System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());
System.out.println();
return CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" - "+Thread.currentThread().getThreadGroup());
return "hello";
},someExecutor);
}
output:
AsyncMethod-1 - java.lang.ThreadGroup[name=main,maxpri=10]
AsyncMethod-2 - java.lang.ThreadGroup[name=main,maxpri=10]
In the second case asyncService() method and supplier in supplyAsync() both are using threads fromsomeExecutor pool
By default, Spring uses a SimpleAsyncTaskExecutor to actually run these async methods, but we overridden that with someExecutor in config using @EnableAsync docs
By default, Spring will be searching for an associated thread pool definition: either a unique TaskExecutor bean in the context, or an Executor bean named "taskExecutor" otherwise. If neither of the two is resolvable, a SimpleAsyncTaskExecutor will be used to process async method invocations.
NOTE : If you don't have @EnableAsync in config class you will get different results, i will upload this code in gitHub and add link here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With