4
头图

Usage and examples of @Async annotation

[TOC]

background

Typically, the method calls in Java are synchronous calls, such as A calls the method B method, in A call B after method, you must wait B method to execute and return later, A method can continue to execute. One problem is that so easily occurs if B method of execution for a long time, it may result in a call A request slow to respond, in order to solve this problem, you can use Spirng comment @Async to use asynchronous Of course, there are other multi-threaded methods to solve such problems. This article mainly analyzes the usage and specific examples of @Async in solving such problems.

Asynchronous call

For example, the method A call the method B , if B is an asynchronous method, A method call B after method, without waiting B method execution is completed, but directly continue down the implementation of other code.

Introduction to @Async

In Spring, marking a method with @Async can make the method into an asynchronous method. When these methods are called, they will be executed in a separate thread, and the caller does not need to wait for the execution of the method to complete.

Enable @Async in Spring

Use @EnableAsync
@Slf4j
@SpringBootApplication
@ComponentScan(basePackages = {"com.kaesar.spring"})
@EnableAsync // 开启异步调用
public class Application {
    public static void main(String[] args) {
        log.info("spring boot开始启动...");
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
        String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
        for (String profile : activeProfiles) {
            log.info("当前环境为:" + profile);
        }
        log.info("spring boot启动成功...");
    }
}

Example 1: Basic usage

Add @Async annotation to the method
/**
 * 异步方法
 * 默认情况下,Spring 使用 SimpleAsyncTaskExecutor 去执行这些异步方法(此执行器没有限制线程数)。
 * 此默认值可以从两个层级进行覆盖:
 * 方法级别
 * 应用级别
 */
@Async
public void test2() {
    try {
        log.info(Thread.currentThread().getName() + " in test2, before sleep.");
        Thread.sleep(2000);
        log.info(Thread.currentThread().getName() + " in test2, after sleep.");
    } catch (InterruptedException e) {
        log.error("sleep error.");
    }
}
call async method
/**
 * 调用不同类的异步方法
 */
public void func1() {
    log.info("before call async function.");
    asyncService.test2();
    log.info("after call async function.");
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        log.error("sleep error.");
    }
    log.info("func end.");
}
Results of the

image.png

It can be seen from the execution results that the func1 method in the main thread does not wait for test2 method to complete and directly executes the following code after calling the asynchronous method test2 .

Example 2: Calling an asynchronous method in the same class

The method func2 and the above async method test2 method are in the same class

image.png

From the execution result, it can be seen that the func2 method in the main thread calls the asynchronous method test2 method, and then waits for test2 method to be executed before continuing.

Example 3: The asynchronous method is a static method

async method test3 is a static method
/**
 * 异步方法不能是 static 方法,不然注解失效
 */
@Async
public static void test3() {
  try {
    log.info(Thread.currentThread().getName() + " in test3, before sleep.");
    Thread.sleep(2000);
    log.info(Thread.currentThread().getName() + " in test3, after sleep.");
  } catch (InterruptedException e) {
    log.error("sleep error.");
  }

}
Method to call test3
/**
 * 调用不同类的异步方法,异步方法是 static 方法
 */
public void func3() {
  log.info(Thread.currentThread().getName() + ": before call async function.");
  AsyncService.test3();
  log.info(Thread.currentThread().getName() + ": after call async function.");
  try {
    Thread.sleep(3000);
  } catch (InterruptedException e) {
    log.error("sleep error.");
  }
  log.info(Thread.currentThread().getName() + ": func end.");
}
Results of the. It can be seen that the @Async annotation is added to the static method. When the method is called, a new thread is not enabled for separate execution, but the code is executed in sequence, indicating that asynchronous is invalid.

image.png

Example 4: Modify the default executor at the method level

Customize a thread pool executor instead of the default executor

Custom thread pool executor

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 自定义线程池
 */
@Configuration
public class AsyncConfig {
    private static final int MAX_POOL_SIZE = 10;
    private static final int CORE_POOL_SIZE = 5;

    @Bean("asyncTaskExecutor")
    public AsyncTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor();
        asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
        asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);
        asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-");
        asyncTaskExecutor.initialize();
        return asyncTaskExecutor;
    }
}
Using custom executors on async methods
/**
 * 在方法级别上修改默认的执行器
 */
@Async("asyncTaskExecutor")
public void test4() {
  try {
    log.info(Thread.currentThread().getName() + ": in test4, before sleep.");
    Thread.sleep(2000);
    log.info(Thread.currentThread().getName() + ": in test4, after sleep.");
  } catch (InterruptedException e) {
    log.error("sleep error.");
  }
}
call test4 asynchronous method
/**
 * 调用不同类的异步方法
 */
public void func4() {
  log.info(Thread.currentThread().getName() + ": before call async function.");
  asyncService.test4();
  log.info(Thread.currentThread().getName() + ": after call async function.");
  try {
    Thread.sleep(3000);
  } catch (InterruptedException e) {
    log.error("sleep error.");
  }
  log.info(Thread.currentThread().getName() + ": func end.");
}

As can be seen from the execution result, the @Async annotation declares that the specified custom asynchronous executor is used, which has replaced the default executor. And the main thread calling the async method is not waiting for the async method to execute.

description: creates a new custom executor, the annotation @Async will be replaced by a custom executor by default, so it is not necessary to specify it on the @Async annotation.

image.png

$1.01^{365} ≈ 37.7834343329$
$0.99^{365} ≈ 0.02551796445$
believe in the power of persistence!

醉舞经阁
1.8k 声望7.1k 粉丝

玉树临风,仙姿佚貌!