Sunday, May 21, 2017

Springframework Async annotation and ThreadExcutor's AbortPolicy

The Springframework has @Async annotation.

it simplifies the asynchronous method execution and hides the implementation details. In order to have a dependable asynchronous execution mechanism, few more factors need our attention.

First, the sample of the usage of the Async annotation:

@Async
void doSomething() {
    // activities will be executed asynchronously
}

@Async("anExecutor")
Future<String> doThenReturnSomething(String id) {
    // will be executed asynchronously
}

Other possible return types:

JDK 8’s java.util.concurrent.CompletableFuture

boolean cancel(boolean mayInterruptIfRunning)
boolean complete(T value)

Spring’s org.springframework.util.concurrent.ListenableFuture 

void      addCallback(ListenableFutureCallback<? super T> callback)
void      addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback)

JBoss’s org.jboss.threads.AsyncFuture

Void asyncCancel(boolean interruptionDesired)
AsyncFuture.Status getStatus()

ThreadPoolTaskExecutor This implementation is the most commonly used one.

<task:executor
        id="executorWithCallerRunsPolicy"
        pool-size="5-25"
        queue-capacity="100"
        keep-alive="120"
        rejection-policy="CALLER_RUNS"/>
From Springframework document:
By default, the queue is unbounded, but this is rarely the desired configuration, because it can lead to OutOfMemoryErrors if enough tasks are added to that queue while all pool threads are busy.

TaskRejectedExceptionAbortPolicyDiscardPolicy or DiscardOldestPolicyCallerRunsPolicy

First, let’s consider the case, as mentioned above, when a task is rejected. By default, when a task is rejected, a thread pool executor will throw a TaskRejectedException. However, the rejection policy is actually configurable. The exception is thrown when using the default rejection policy which is the AbortPolicy implementation. For applications where some tasks can be skipped under heavy load, either the DiscardPolicy or DiscardOldestPolicy may be configured instead. Another option that works well for applications that need to throttle the submitted tasks under heavy load is the CallerRunsPolicy. Instead of throwing an exception or discarding tasks, that policy will simply force the thread that is calling the submit method to run the task itself. The idea is that such a caller will be busy while running that task and not able to submit other tasks immediately. Therefore it provides a simple way to throttle the incoming load while maintaining the limits of the thread pool and queue. Typically this allows the executor to "catch up" on the tasks it is handling and thereby frees up some capacity on the queue, in the pool, or both. Any of these options can be chosen from an enumeration of values available for the 'rejection-policy' attribute on the 'executor' element.
The keep-alive setting determines the time limit (in seconds) for which threads may remain idle before being terminated. If there are more than the core number of threads currently in the pool, after waiting this amount of time without processing a task, excess threads will get terminated.
Finally,
When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as submit, these task objects catch and maintain computational exceptions, and so they do not cause abrupt termination, and the internal exceptions are not passed to this method. Please make sure that the calling method handles the exception properly.
Inside the asynchronous task, most likely, a remote service call or database access will be invoked. Please configure proper timeout so that thread will not be blocked or thread will not hang.

No comments:

Post a Comment