🎓博主介绍:Java、Python、js全栈开发 “多面手”,精通多种编程语言和技术,痴迷于人工智能领域。秉持着对技术的热爱与执着,持续探索创新,愿在此分享交流和学习,与大家共进步。
📖DeepSeek-行业融合之万象视界(附实战案例详解100+)
📖全栈开发环境搭建运行攻略:多语言一站式指南(环境搭建+运行+调试+发布+保姆级详解)
👉感兴趣的可以先收藏起来,希望帮助更多的人
SpringBoot异步编程实战:@Async与CompletableFuture深度剖析
一、引言
在现代软件开发中,随着业务逻辑的日益复杂和用户对系统响应速度要求的不断提高,异步编程逐渐成为提升系统性能和响应能力的重要手段。Spring Boot作为一款广泛应用的Java开发框架,提供了强大的异步编程支持,其中@Async注解和CompletableFuture类是实现异步编程的两个关键工具。本文将深入剖析这两种异步编程方式,通过实战案例帮助技术人员掌握它们的使用方法和应用场景。
二、Spring Boot异步编程基础
2.1 同步编程与异步编程的区别
- 同步编程:在同步编程模型中,程序按照顺序依次执行每个任务,只有当前任务完成后,才会继续执行下一个任务。这种方式简单直观,但在处理耗时操作时会阻塞线程,导致系统响应变慢。
- 异步编程:异步编程允许程序在执行耗时操作时不阻塞当前线程,而是继续执行其他任务。当耗时操作完成后,通过回调、事件等方式通知主线程。这种方式可以提高系统的并发性能和响应能力。
2.2 Spring Boot异步编程的优势
- 提高系统性能:通过异步处理耗时任务,释放主线程资源,使系统能够同时处理更多的请求。
- 改善用户体验:减少用户等待时间,提高系统的响应速度,增强用户体验。
- 简化代码结构:使用异步编程可以将复杂的业务逻辑拆分成多个独立的任务,使代码结构更加清晰。
三、@Async注解的使用
3.1 开启异步支持
在Spring Boot项目中,要使用@Async注解实现异步方法,首先需要在主应用类上添加@EnableAsync注解来开启异步支持。示例代码如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
3.2 创建异步方法
在需要异步执行的方法上添加@Async注解。示例代码如下:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class AsyncService {
@Async
public void asyncMethod() {
try {
// 模拟耗时操作
TimeUnit.SECONDS.sleep(5);
System.out.println("异步方法执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3.3 调用异步方法
在其他服务类或控制器中调用异步方法。示例代码如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/async")
public String asyncRequest() {
asyncService.asyncMethod();
return "异步请求已发送";
}
}
3.4 异步方法的返回值
@Async注解的方法可以有返回值,但返回值类型必须是Future或其子类。示例代码如下:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public Future<String> asyncMethodWithResult() {
try {
TimeUnit.SECONDS.sleep(5);
return CompletableFuture.completedFuture("异步方法执行结果");
} catch (InterruptedException e) {
e.printStackTrace();
return CompletableFuture.completedFuture("执行出错");
}
}
}
调用带有返回值的异步方法:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Future;
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/async-result")
public String asyncRequestWithResult() throws Exception {
Future<String> result = asyncService.asyncMethodWithResult();
// 等待异步方法执行完成并获取结果
while (!result.isDone()) {
Thread.sleep(100);
}
return result.get();
}
}
3.5 自定义线程池
默认情况下,@Async使用Spring的默认线程池。为了更好地控制异步任务的执行,我们可以自定义线程池。示例代码如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(25);
executor.setThreadNamePrefix("Async-");
executor.initialize();
return executor;
}
}
在@Async注解中指定使用自定义线程池:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class AsyncService {
@Async("asyncExecutor")
public void asyncMethod() {
try {
TimeUnit.SECONDS.sleep(5);
System.out.println("异步方法执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
四、CompletableFuture的使用
4.1 CompletableFuture简介
CompletableFuture是Java 8引入的一个强大的异步编程工具,它实现了Future和CompletionStage接口,提供了丰富的方法来处理异步任务的结果和组合多个异步任务。
4.2 创建CompletableFuture
- 使用
runAsync方法创建无返回值的异步任务:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(2000);
System.out.println("异步任务执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, executor);
// 主线程继续执行其他任务
System.out.println("主线程继续执行");
// 等待异步任务完成
future.join();
executor.shutdown();
}
}
- 使用
supplyAsync方法创建有返回值的异步任务:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "异步任务执行结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
}, executor);
// 主线程继续执行其他任务
System.out.println("主线程继续执行");
// 等待异步任务完成并获取结果
String result = future.join();
System.out.println("异步任务结果: " + result);
executor.shutdown();
}
}
4.3 处理CompletableFuture的结果
- 使用
thenApply方法处理异步任务的结果:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "异步任务执行结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
});
CompletableFuture<String> processedFuture = future.thenApply(result -> {
return result.toUpperCase();
});
String finalResult = processedFuture.join();
System.out.println("处理后的结果: " + finalResult);
}
}
- 使用
thenAccept方法消费异步任务的结果:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "异步任务执行结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
});
future.thenAccept(result -> {
System.out.println("消费结果: " + result);
});
// 等待异步任务完成
future.join();
}
}
4.4 组合多个CompletableFuture
- 使用
thenCompose方法组合两个CompletableFuture:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "第一个异步任务结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
});
CompletableFuture<String> future2 = future1.thenCompose(result -> {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return result + " 第二个异步任务结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
});
});
String finalResult = future2.join();
System.out.println("组合后的结果: " + finalResult);
}
}
- 使用
thenCombine方法组合两个CompletableFuture:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "第一个异步任务结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "第二个异步任务结果";
} catch (InterruptedException e) {
e.printStackTrace();
return "执行出错";
}
});
CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
return result1 + " " + result2;
});
String finalResult = combinedFuture.join();
System.out.println("组合后的结果: " + finalResult);
}
}
4.5 异常处理
使用exceptionally方法处理异步任务中的异常:
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("模拟异常");
});
CompletableFuture<String> handledFuture = future.exceptionally(ex -> {
return "异常处理结果: " + ex.getMessage();
});
String result = handledFuture.join();
System.out.println(result);
}
}
五、@Async与CompletableFuture的比较
5.1 适用场景
- @Async:适用于简单的异步任务,不需要复杂的任务组合和结果处理。例如,在Spring Boot应用中处理一些耗时的日志记录、消息发送等任务。
- CompletableFuture:适用于复杂的异步任务,需要进行任务组合、结果处理和异常处理。例如,在微服务架构中,需要同时调用多个服务并处理它们的结果。
5.2 性能差异
- @Async:使用Spring的线程池管理异步任务,性能相对稳定,但在处理复杂任务时可能不够灵活。
- CompletableFuture:提供了更细粒度的任务控制和并发处理能力,性能更高,但代码复杂度也相对较高。
5.3 代码复杂度
- @Async:代码简单,只需要在方法上添加注解即可实现异步调用。
- CompletableFuture:代码复杂度较高,需要使用各种方法来处理异步任务的结果和组合多个任务。
六、实战案例:综合应用@Async与CompletableFuture
6.1 需求描述
假设我们有一个电商系统,需要同时查询商品信息、用户信息和订单信息,并将这些信息整合后返回给用户。为了提高系统的响应速度,我们可以使用异步编程来并行查询这些信息。
6.2 代码实现
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class DataService {
@Async
public CompletableFuture<String> getProductInfo() {
try {
Thread.sleep(2000);
return CompletableFuture.completedFuture("商品信息");
} catch (InterruptedException e) {
e.printStackTrace();
return CompletableFuture.failedFuture(e);
}
}
@Async
public CompletableFuture<String> getUserInfo() {
try {
Thread.sleep(1500);
return CompletableFuture.completedFuture("用户信息");
} catch (InterruptedException e) {
e.printStackTrace();
return CompletableFuture.failedFuture(e);
}
}
@Async
public CompletableFuture<String> getOrderInfo() {
try {
Thread.sleep(1800);
return CompletableFuture.completedFuture("订单信息");
} catch (InterruptedException e) {
e.printStackTrace();
return CompletableFuture.failedFuture(e);
}
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@RestController
public class DataController {
@Autowired
private DataService dataService;
@GetMapping("/data")
public String getData() throws ExecutionException, InterruptedException {
CompletableFuture<String> productFuture = dataService.getProductInfo();
CompletableFuture<String> userFuture = dataService.getUserInfo();
CompletableFuture<String> orderFuture = dataService.getOrderInfo();
CompletableFuture<Void> allFutures = CompletableFuture.allOf(productFuture, userFuture, orderFuture);
CompletableFuture<String> combinedFuture = allFutures.thenApply(v -> {
try {
return productFuture.get() + " " + userFuture.get() + " " + orderFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return "执行出错";
}
});
return combinedFuture.get();
}
}
七、总结
本文深入剖析了Spring Boot中@Async注解和CompletableFuture类的使用方法和应用场景。@Async注解提供了简单的异步方法调用功能,适用于处理简单的异步任务;而CompletableFuture类则提供了更强大的异步任务处理和组合能力,适用于处理复杂的异步场景。通过合理使用这两种异步编程方式,可以显著提高Spring Boot应用的性能和响应能力。

5415

被折叠的 条评论
为什么被折叠?



