说明
此 demo 主要演示了 Spring Boot 如何使用原生提供的异步任务支持,实现异步执行任务
注意事项
在使用 Spring Async 进行异步编程时,需要注意以下几点:
- 使用 @Async 注解将方法标记为异步方法。
- 异步方法必须在 public 方法中定义,并且不能在同一类中调用本类中的其他异步方法,否则其将会同步执行。
- Spring Async 默认的执行器是 SimpleAsyncTaskExecutor,可以通过配置实现使用自定义的执行器。
- 异步方法无法获取其返回值,必须通过 Future 或 CompletableFuture 来获取其执行结果。
- 异步方法在抛出异常时,异常会被封装到 Future 或 CompletableFuture 中,必须使用 try-catch 或者通过 Future 或 CompletableFuture 的回调方法来处理异常
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-demo-async</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging>
<name>spring-boot-demo-async</name> <description>Demo project for Spring Boot</description>
<parent> <groupId>com.xkcoding</groupId> <artifactId>spring-boot-demo</artifactId> <version>1.0.0-SNAPSHOT</version> </parent>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies>
<build> <finalName>spring-boot-demo-async</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
|
application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| spring: task: execution: pool: max-size: 16 core-size: 16 keep-alive: 10s queue-capacity: 100 allow-core-thread-timeout: true thread-name-prefix: async-task-
|
SpringBootDemoAsyncApplication.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@EnableAsync @SpringBootApplication public class SpringBootDemoAsyncApplication {
public static void main(String[] args) { SpringApplication.run(SpringBootDemoAsyncApplication.class, args); } }
|
TaskFactory.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
@Component @Slf4j public class TaskFactory {
@Async public Future<Boolean> asyncTask1() throws InterruptedException { doTask("asyncTask1", 5); return new AsyncResult<>(Boolean.TRUE); }
@Async public Future<Boolean> asyncTask2() throws InterruptedException { doTask("asyncTask2", 2); return new AsyncResult<>(Boolean.TRUE); }
@Async public Future<Boolean> asyncTask3() throws InterruptedException { doTask("asyncTask3", 3); return new AsyncResult<>(Boolean.TRUE); }
public void task1() throws InterruptedException { doTask("task1", 5); }
public void task2() throws InterruptedException { doTask("task2", 2); }
public void task3() throws InterruptedException { doTask("task3", 3); }
private void doTask(String taskName, Integer time) throws InterruptedException { log.info("{}开始执行,当前线程名称【{}】", taskName, Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(time); log.info("{}执行成功,当前线程名称【{}】", taskName, Thread.currentThread().getName()); } }
|
TaskFactoryTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
@Slf4j public class TaskFactoryTest extends SpringBootDemoAsyncApplicationTests { @Autowired private TaskFactory task;
@Test public void asyncTaskTest() throws InterruptedException, ExecutionException { long start = System.currentTimeMillis(); Future<Boolean> asyncTask1 = task.asyncTask1(); Future<Boolean> asyncTask2 = task.asyncTask2(); Future<Boolean> asyncTask3 = task.asyncTask3();
asyncTask1.get(); asyncTask2.get(); asyncTask3.get(); long end = System.currentTimeMillis();
log.info("异步任务全部执行结束,总耗时:{} 毫秒", (end - start)); }
@Test public void taskTest() throws InterruptedException { long start = System.currentTimeMillis(); task.task1(); task.task2(); task.task3(); long end = System.currentTimeMillis();
log.info("同步任务全部执行结束,总耗时:{} 毫秒", (end - start)); } }
|
运行结果
异步任务
1 2 3 4 5 6 7
| 2018-12-29 10:57:28.511 INFO 3134 --- [ async-task-3] com.xkcoding.async.task.TaskFactory : asyncTask3开始执行,当前线程名称【async-task-3】 2018-12-29 10:57:28.511 INFO 3134 --- [ async-task-1] com.xkcoding.async.task.TaskFactory : asyncTask1开始执行,当前线程名称【async-task-1】 2018-12-29 10:57:28.511 INFO 3134 --- [ async-task-2] com.xkcoding.async.task.TaskFactory : asyncTask2开始执行,当前线程名称【async-task-2】 2018-12-29 10:57:30.514 INFO 3134 --- [ async-task-2] com.xkcoding.async.task.TaskFactory : asyncTask2执行成功,当前线程名称【async-task-2】 2018-12-29 10:57:31.516 INFO 3134 --- [ async-task-3] com.xkcoding.async.task.TaskFactory : asyncTask3执行成功,当前线程名称【async-task-3】 2018-12-29 10:57:33.517 INFO 3134 --- [ async-task-1] com.xkcoding.async.task.TaskFactory : asyncTask1执行成功,当前线程名称【async-task-1】 2018-12-29 10:57:33.517 INFO 3134 --- [ main] com.xkcoding.async.task.TaskFactoryTest : 异步任务全部执行结束,总耗时:5015 毫秒
|
同步任务
1 2 3 4 5 6 7
| 2018-12-29 10:55:49.830 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactory : task1开始执行,当前线程名称【main】 2018-12-29 10:55:54.834 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactory : task1执行成功,当前线程名称【main】 2018-12-29 10:55:54.835 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactory : task2开始执行,当前线程名称【main】 2018-12-29 10:55:56.839 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactory : task2执行成功,当前线程名称【main】 2018-12-29 10:55:56.839 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactory : task3开始执行,当前线程名称【main】 2018-12-29 10:55:59.843 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactory : task3执行成功,当前线程名称【main】 2018-12-29 10:55:59.843 INFO 3079 --- [ main] com.xkcoding.async.task.TaskFactoryTest : 同步任务全部执行结束,总耗时:10023 毫秒
|
参考