@Async Overview
In Spring用@Async注解标记的方法,称为异步方法
, it will be executed in an independent thread outside the current thread of the caller,
- In fact, it is equivalent to ourselves
new Thread(()-> System.out.println("hello world !"))
executing the corresponding business logic in another thread
异步方法实际的执行交给了 Spring 的 TaskExecutor 来完成。
@Async use
- @Async annotation If is used on a class method, it means that the method is an asynchronous method
- @Async annotation If is used on a class, then all methods of this class will be executed asynchronously
- The class object of the @Async annotation method should be a bean object managed by the Spring container
调用异步方法类上需要配置上注解@EnableAsync,或者是在启动类上加上@EnableAsync
@Async note
- By default (@EnableAsync annotated
mode=AdviceMode.PROXY
),同一个类内部没有使用@Async注解修饰的方法调用@Async注解修饰的方法,是不会异步执行的
- If you want
实现类内部自调用也可以异步
, you need to switch the mode= of the @EnableAsync annotationAdviceMode.ASPECTJ
- Any parameter type is supported, but the method return value must be void or Future type
@Async code example
Use 1 code implementation: Configure @EnableAsync on the class to call the asynchronous method
import org.springframework.scheduling.annotation.Async;
public interface TestService {
@Async
void test();
}
import com.example.service.TestService;
import org.springframework.stereotype.Service;
@Service
public class TestServiceImpl implements TestService {
@Override
public void test() {
//...
}
}
Controller class that calls asynchronous methods
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/test")
@EnableAsync
public class TestContoller {
@Autowired
private TestService testService;
@GetMapping(value = "/testAsync")
public void print() {
testService.test();
}
}
If we remove @EnableAsync on the TestController or create a new TestService object (the object is not loaded into the Spring container), then the print() method in the TestController will be executed synchronously, and the background printing log can also see that only one thread is executing.
Implemented using 2 codes: configure @EnableAsync on the startup class
If @EnableAsync is configured on the startup class, then in the above example code, there is no need to add the @EnableAsync annotation on the Controller
入口类增加了 @EnableAsync 注解,主要是为了扫描范围包下的所有 @Async 注解。
Note 1 code implementation: @Async does not take effect
@Async modifies the test() method, but the test2() method does not modify it
public interface TestService {
@Async
void test();
void test2();
}
public class TestServiceImpl implements TestService{
@Override
public void test() {
//...
}
@Override
public void test2() {
test();//自调用test()方法
}
}
In this case:The test() method called by the test2() method is not executed asynchronously, there is only one thread
AsyncResult
Spring中提供了一个 Future 接口的子类:AsyncResult,所以我们可以返回 AsyncResult 类型的值。
AsyncResult is an asynchronous method. Asynchronous is mainly used for calling code that needs to run for a long time to return results without blocking the caller.
public class AsyncResult<V> implements ListenableFuture<V> {
private final V value;
private final ExecutionException executionException;
//...
}
AsyncResult implements the ListenableFuture interface. This object has two properties: return value and exception information.
public interface ListenableFuture<T> extends Future<T> {
void addCallback(ListenableFutureCallback<? super T> var1);
void addCallback(SuccessCallback<? super T> var1, FailureCallback var2);
}
AsyncResult code example
Get the implementation of the asynchronous method return value: return String
public Future<String> test() throws Exception {
log.info("开始做任务");
long start = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
log.info("完成任务,耗时:" + (end - start) + "毫秒");
return new AsyncResult<>("任务完成,耗时" + (end - start) + "毫秒");
}
If a custom type is returned, the String in the Future above is changed to the corresponding entity class.
CompletableFuture
To count how much time it takes to execute the three tasks concurrently, you need to wait until the above three functions have been mobilized, record the time, and calculate the results.
You can also use CompletableFuture to return the results of asynchronous calls
- Use CompletableFuture.allOf(task1, task2, task3).join() to achieve the blocking effect before the three asynchronous tasks end.
- After all three tasks are completed, calculate the total time taken for the concurrent execution of the three tasks based on the end time - start time.
CompletableFuture code example
@Async
public CompletableFuture<String> doTaskOne() throws Exception {
log.info("开始做任务一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("完成任务一,耗时:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("任务一完成");
}
@Test
public void test() throws Exception {
long start = System.currentTimeMillis();
CompletableFuture<String> task1 = asyncTasks.test();
CompletableFuture<String> task2 = asyncTasks.test();
CompletableFuture<String> task3 = asyncTasks.test();
CompletableFuture.allOf(task1, task2, task3).join();
long end = System.currentTimeMillis();
log.info("任务全部完成,总耗时:" + (end - start) + "毫秒");
}
Thread pool configuration
Google or Baidu, spring thread pool configuration, basically very detailed