I have a asynchronous method enabled using #Async annotation. At times i am seeing SimpleAsyncTaskExecutor thread count increases exponentially. Any idea on this behavior?
If it increases literally exponentially it sounds like the async method is calling itself perhaps?
By default, Spring uses a SimpleAsyncTaskExecutor to run the methods asynchronously.
SimpleAsyncTaskExecutor spawns a new thread with each task and does not support thread pooling and queueing of tasks.
So, if the async method is called multiple times in a short span of time, multiple threads will be opened for each task
You should define your own executor. Refer the following link
http://www.baeldung.com/spring-async
Related
The project I am working for is using Spring WebFlux. I came across a very odd issue.
The detail is that some of pieces of code are purely wrote in Reactor style (couples of Flux/Mono pipelines), however, in a inner publishers, I have to call a method where there is "Mono.block()" inside.
The weird thing I aware is that the whole service would become totally stuck, and when I captured a thread dump, I saw all those "nioEventLoopGroup-*" threads were hung.
A fun fact is that if I leverage a "simple" thread (new Thread(..)) to call the method (there is .block inside), everything works fine.
So my question is that, are those "nioEventLoopGroup-*" threads not allowed to call any blocking code.
Sorry for asking a dumb question, but it's blocking issue for now, so I am looking forward your insight.
Reactor, by default, uses a fixed size thread pool. When you use block(), the actual work needs to be done in some thread or another, which depends on the nature of the subscription and the Mono/Flux. Most likely a set of new tasks will be scheduled on the same scheduler, but block() will suspend its thread, waiting for those tasks to complete, so there is one fewer thread for those other tasks to be scheduled on. Evidently you have enough of these calls to exhauast the entire thread pool. All your block() calls are waiting for other tasks to complete, but there are no threads available for them to be run on.
There's no reason to call block() inside a mapping in a reactive stream. There are always other ways of achieving the same goal without blocking - flatMap(), zip() etc etc.
I have a Spring boot 2.1.6.RELEASE application in which I have a method annotated with
#Scheduled(cron = "*/10 * * * * *}
I want it to run with that cron, EVEN IF another execution is already in progress.
I tried increasing the executor thread number using the application.properties file:
spring.task.scheduling.pool.size=10
But it didn't seem to work as it is still waiting for an execution to finish before starting the next one.
What is the proper way to do parallel executions using a cron in the #Scheduled annotation?
It is true that the default pool size for the task scheduler is 1 but increasing this pool size is only making more threads available for other #Scheduled methods. The intended behaviour is not for methods to run in parallel as otherwise threads could become exhausted.
If you wish to change this behaviour to allow the same method to run in parallel you need to use #EnableAsync and #Async annotations. You might also want to change the pool size of the task executor. That being said, keep in mind that you may still exhaust your threads so be very careful with changing this intended behaviour.
Do we really required to have Executor for #Async in Spring?
What will happen if i am not using Executor interface on the front of thread pool?
When no custom TaskExecutor is given, or other in other words out-of-box spring uses SimpleAsyncTaskExecutor to create threads to handle async.
SimpleAsyncTaskExecutor -
By default concurrent threads is unlimited. Supports control by concurrencyLimit property
No re-use of threads
TaskExecutor based -
Allows to have thread pool with limited number of threads as required
Since we use thread pools, re-use of threads is done and no overhead.
Javadoc : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/task/SimpleAsyncTaskExecutor.html
I'm using spring's abstraction ThreadPoolTaskExecutor in order to execute tasks using threads.
The execute method described as (java doc):
Execute the given task.
The call might return immediately if the implementation uses an asynchronous execution strategy, or might block in the case of synchronous execution.
Got 2 questions:
Where can the execution strategy be configured?
If the execution strategy is set to "synchronous", how can it serve me? It seems weird to use an executor that works synchronously.
Say I have an #Async method call that hangs. Will it time out? What is best practise here to free you resources?
#Async method invocations are executed within a specified thread pool. If your method hangs, it will hold one thread from the pool infinitely. Spring can't do anything about it.
If your method is kind enough to accept InterruptedException, you can cancel it by calling Future.cancel() on a value returned from asynchronous method.