For asynchronous method calls, an @async annotation is provided starting with Spring3, which can be tagged to a method to call it asynchronously. The caller will return immediately upon invocation, and the actual execution of the method will be submitted to the Spring TaskExecutor task and executed by threads in the specified thread pool.

In project applications, @async invokes a thread pool, and the custom thread pool pattern is recommended. Custom thread pool common solution: re-implement AsyncConfigurer interface.

Application scenarios

Synchronization: Synchronization is the sequential execution of the entire process, when each process is completed, and the result is returned.

Asynchronous: Asynchronous invocation is just to send the instruction of the invocation, the caller does not need to wait for the method to be called to complete execution; Instead, proceed with the following process. For example, in A call, procedure methods A, B, and C need to be called sequentially. If they are all synchronous calls, the procedure execution is completed only after they are all executed sequentially. For example, if B is an asynchronous calling method, after executing A, B will be called. Instead of waiting for B to complete, C will be called. After executing C, it means that the process is finished. In Java, similar scenarios are generally handled based on the creation of a separate thread to complete the corresponding asynchronous invocation logic, through the execution process between the main thread and different business child threads, so that after the independent thread is started, the main thread continues to execute without the situation of stagnation.

Thread pools that Spring has implemented

  • SimpleAsyncTaskExecutor: Not a real thread pool. This class does not reuse threads and by default creates a new thread each time it is called.
  • SyncTaskExecutor: This class does not implement an asynchronous call, just a synchronous operation. Only applicable where multithreading is not required.
  • ConcurrentTaskExecutor: Executor adaptation class. This class is not recommended. Consider using this class only if ThreadPoolTaskExecutor does not meet the requirements.
  • SimpleThreadPoolTaskExecutor: is Quartz SimpleThreadPool class. This class is required only if thread pools are used by both Quartz and non-Quartz.
  • **ThreadPoolTaskExecuto**r: Most commonly used, recommended. The essence of which is the Java. Util. Concurrent. ThreadPoolExecutor packaging.

There are asynchronous methods

  • Simplest asynchronous call, returns void
  • An asynchronous call with parameters that an asynchronous method can pass in
  • There is a return value, often called return Future

Enable @async in Spring

支那

支那

@async applies the default thread pool

Spring applies the default thread pool, meaning that the @async annotation is used without specifying the name of the thread pool. The default thread pool for @async is SimpleAsyncTaskExecutor.

  • Call with no return value

Based on @async calls with no return value, annotate directly on using class, using method (suggest using method). If an exception needs to be thrown, manually create a new exception to be thrown.

  • There is a return value Future call

  • Returns a valueCompletableFuturecall

**CompletableFuture** does not use the @async annotation to call the system thread pool to process the business.

JDK5 adds a Future interface to describe the result of an asynchronous calculation. While Future and related usage methods provide the ability to execute tasks asynchronously, it is very inconvenient to obtain results, which can only be obtained through blocking or polling. Blocking works against the purpose of asynchronous programming, polling uses unnecessary CPU resources and doesn’t get results in a timely manner.

  • The CompletionStage represents a stage in an asynchronous calculation, and the completion of one stage may trigger another

  • A stage of computation execution can be a Function, Consumer, or Runnable. Such as:

    stage.thenApply(x -> square(x)).thenAccept(x -> System.out.print(x)).thenRun(() -> System.out.println())

  • The execution of a phase may be triggered by the completion of a single phase or by several phases at once

In Java8, CompletableFuture offers a very powerful Future extension that helps simplify the complexity of asynchronous programming, and provides the ability to do functional programming with callbacks to compute results, Methods to transform and compose CompletableFutures are also provided.

  • It may represent a Future that is explicitly completed, or it may represent a CompletionStage that allows functions to be triggered or actions to be performed after the computation is complete.

  • It implements the Future and CompletionStage interfaces

  • Disadvantages of the default thread pool

In thread pool application, refer to Alibaba Java development specification: Do not use Executors to create a thread pool or use the default thread pool. You are advised to use ThreadPoolExecutor to clarify the running rules of the thread pool and avoid resource depletion. Executors disadvantages of each method:

  • NewFixedThreadPool and newSingleThreadExecutor: The main problem is that the stacked request processing queue can consume a lot of memory or even OOM.
  • NewCachedThreadPool and newScheduledThreadPool: If the maximum number of threads is integer. MAX_VALUE, a very large number of threads may be created, or even OOM.

The @Async default Async configuration uses SimpleAsyncTaskExecutor. By default, this thread pool creates one thread for each task. If the system continuously creates threads, the system will eventually occupy too much memory and raise OutOfMemoryError. For thread creation problems, SimpleAsyncTaskExecutor provides a traffic limiting mechanism. The concurrencyLimit property is used to control the flow limiting. When concurrencyLimit>=0, the traffic limiting mechanism is enabled. ConcurrencyLimit =-1 is disabled by default. When concurrencyLimit is disabled, new threads are constantly created to process tasks. Based on the default configuration, SimpleAsyncTaskExecutor is not strictly a thread pool and cannot be used for thread reuse.

@async Applies a custom thread pool

Custom thread pool, more fine-grained control of the system thread pool, easy to adjust the size of the thread pool configuration, thread to perform exception control and processing. The default thread pool can be replaced by a system custom thread pool. However, the default thread pool can be replaced by only one thread pool (AsyncConfigurer cannot be set to multiple classes).

  • Re-implement the interface AsyncConfigurer
  • Inheritance AsyncConfigurerSupport
  • Configure a custom TaskExecutor to replace the built-in TaskExecutor

By looking at the Spring source code’s default invocation rules for @async, the class that implements the AsyncConfigurer interface is preferentially searched. The class that implements the interface is asyncConfigerSupport. However, the default configured thread pool and asynchronous processing methods are empty, so you need to specify a thread pool for either inheriting or reimplementing the interface. And re-implement the public Executor getAsyncExecutor() method.

  • Implement the interface AsyncConfigurer

  • Inheritance AsyncConfigurerSupport

  • Configure a custom TaskExecutor

Since AsyncConfigurer’s default thread pool is null in the source code, Spring uses beanFactory.getBean(TaskExecutor.class) to check if there is a thread pool. The beanfactory.getbean (DEFAULT_TASK_EXECUTOR_BEAN_NAME, executor.class) command is used to check whether there is a thread pool whose default name is TaskExecutor. So in your project, define a bean named TaskExecutor to generate a default thread pool. You may not specify the name of the thread pool, but declare a thread pool that is itself based on taskExecutor.class.

Such as:

Executor.class:ThreadPoolExecutorAdapter->ThreadPoolExecutor->AbstractExecutorService->ExecutorService->Executor
Copy the code

Class. When you replace the default thread pool, you need to set the default thread pool name to TaskExecutor

TaskExecutor.class:ThreadPoolTaskExecutor->SchedulingTaskExecutor->AsyncTaskExecutor->TaskExecutor
Copy the code

Taskexecutor.class, which replaces the default thread pool without specifying the thread pool name.

More technical articles to share, wechat search a search: code farming architecture

Why does Alibaba not recommend using Async annotations directly?