当前位置: 首页 > news >正文

Java 原生异步编程与Spring 异步编程 详解

简介

Java 异步编程是现代高性能应用开发的核心技术之一,它允许程序在执行耗时操作(如网络请求、文件 IO)时不必阻塞主线程,从而提高系统吞吐量和响应性。

异步 vs 同步

  • 同步:任务按顺序执行,后续任务需等待前任务完成。
public String syncTask() {// 模拟耗时操作Thread.sleep(1000);return "Result";
}
  • 异步:任务并行或在后台执行,主线程立即返回。
public CompletableFuture<String> asyncTask() {return CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return "Result";});
}

Java 原生异步支持

手动创建线程

最基本的异步方式是创建 Thread 或实现 Runnable

  • 缺点:管理线程池困难,资源浪费,难以复用,缺乏结果处理机制。
public class BasicAsync {public static void main(String[] args) {Thread thread = new Thread(() -> {try {Thread.sleep(1000);System.out.println("Task completed");} catch (InterruptedException e) {e.printStackTrace();}});thread.start();System.out.println("Main thread continues");}
}
使用 ExecutorService
  • 优点:提供线程池管理,复用线程,减少创建开销

  • 缺点:Future.get() 是阻塞的,难以链式调用

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);executor.submit(() -> {Thread.sleep(1000);System.out.println("Task 1 completed");});executor.submit(() -> {Thread.sleep(500);System.out.println("Task 2 completed");});executor.shutdown();}
}
常用方法:
  • submit(Runnable):提交无返回值的任务。

  • submit(Callable):提交有返回值的任务,返回 Future

  • shutdown():关闭线程池,不接受新任务。

线程池类型:
  • Executors.newFixedThreadPool(n):固定大小线程池。

  • Executors.newCachedThreadPool():动态调整线程数。

  • Executors.newSingleThreadExecutor():单线程执行。

线程池类型对比:

类型特性适用场景
FixedThreadPool固定线程数,无界队列负载稳定的长期任务
CachedThreadPool自动扩容,60秒闲置回收短时突发任务
ScheduledThreadPool支持定时/周期性任务心跳检测、定时报表
WorkStealingPool使用 ForkJoinPool,任务窃取算法计算密集型并行任务
Future(Java 5+)
import java.util.concurrent.*;public class FutureExample {public static void main(String[] args) throws Exception {ExecutorService executor = Executors.newFixedThreadPool(1);Future<String> future = executor.submit(() -> {Thread.sleep(1000);return "Task completed";});// 主线程继续System.out.println("Doing other work");// 阻塞获取结果String result = future.get(); // 等待任务完成System.out.println(result);executor.shutdown();}
}
方法
  • get():阻塞获取结果。

  • isDone():检查任务是否完成。

  • cancel(boolean):取消任务。

缺点
  • get() 是阻塞的,不利于非阻塞编程。

  • 难以组合多个异步任务。

CompletableFuture(Java 8+)

支持链式调用,真正现代化异步编程方式。

import java.util.concurrent.CompletableFuture;public class CompletableFutureExample {public static void main(String[] args) {CompletableFuture.supplyAsync(() -> {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return "Task result";}).thenApply(result -> result.toUpperCase()) // 转换结果.thenAccept(result -> System.out.println(result)) // 消费结果.exceptionally(throwable -> {System.err.println("Error: " + throwable.getMessage());return null;});System.out.println("Main thread continues");}
}
虚拟线程(Java 21+,Project Loom)

虚拟线程是 Java 21 引入的轻量级线程,适合高并发 I/O 密集型任务。

public class VirtualThreadExample {public static void main(String[] args) {try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {executor.submit(() -> {try {Thread.sleep(1000);System.out.println("Task completed in virtual thread");} catch (InterruptedException e) {e.printStackTrace();}});}System.out.println("Main thread continues");}
}

优势

  • 轻量级,创建开销极低(相比传统线程)。

  • 适合 I/O 密集型任务(如 HTTP 请求、数据库查询)。

注意

  • 不适合 CPU 密集型任务(可能导致线程饥饿)。

  • Spring Boot 3.2+ 支持虚拟线程(需配置)。

阻塞 vs 非阻塞
类型是否阻塞获取结果方式
Future<T>✅ 是future.get()(阻塞)
CompletableFuture<T>✅(get) ❌(then)支持非阻塞链式处理
@Async + Future/CompletableFutureget() 或回调
WebFlux❌ 完全非阻塞响应式 Mono / Flux
Future<T> vs CompletableFuture<T>:核心对比
功能Future<T>CompletableFuture<T>
Java 版本Java 5+Java 8+
是否可组合❌ 不支持✅ 支持链式组合、并行执行
支持异步回调❌ 无✅ 有 .thenApply().thenAccept()
支持异常处理❌ 无✅ 有 .exceptionally()
可取消✅ 支持 cancel()✅ 也支持
阻塞获取get() 阻塞get() 阻塞(也可非阻塞)
使用场景简单线程任务多异步任务组合、复杂控制流

Spring 异步编程(基于 @Async)

配置类或启动类启用异步支持
@SpringBootApplication
@EnableAsync
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
@Configuration
@EnableAsync
public class AsyncConfig {
}
无返回值用法
// 无返回值的异步方法
@Async
public void sendEmail(String to) {System.out.println("异步发送邮件给: " + to);try { Thread.sleep(2000); } catch (InterruptedException e) {}System.out.println("邮件发送完成");
}
使用 Future<T>

创建异步方法

@Service
public class AsyncService {@Asyncpublic Future<String> processTask() {// 模拟耗时操作return new AsyncResult<>("Task completed");}
}

调用并获取结果:

@Autowired
private AsyncService asyncService;public void executeTask() throws Exception {Future<String> future = asyncService.processTask();String result = future.get(); // 阻塞等待结果
}
使用 CompletableFuture<T>

创建异步方法

@Async
public CompletableFuture<String> asyncMethod() {return CompletableFuture.completedFuture("Async Result");
}

调用方式:

CompletableFuture<String> result = asyncService.asyncMethod();
// 非阻塞,可以做其他事
String value = result.get(); // 阻塞获取
线程池配置
使用自定义配置类
@Configuration
public class AsyncConfig {@Bean("taskExecutor")public Executor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);      // 核心线程数executor.setMaxPoolSize(20);      // 最大线程数executor.setQueueCapacity(100);   // 队列容量executor.setKeepAliveSeconds(30); // 空闲线程存活时间executor.setThreadNamePrefix("async-task-");executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}
}// 指定线程池
@Async("taskExecutor")
public Future<String> customPoolTask() { ... }
使用配置文件
# application.yml
spring:task:execution:pool:core-size: 5max-size: 20queue-capacity: 100thread-name-prefix: async-shutdown:await-termination: trueterminate-on-timeout: true
Spring WebFlux 示例
@Service
public class UserService {public Mono<String> getUser() {return Mono.just("用户信息").delayElement(Duration.ofSeconds(2));}public Flux<String> getAllUsers() {return Flux.just("用户1", "用户2", "用户3").delayElements(Duration.ofSeconds(1));}
}
@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/one")public Mono<String> getUser() {return userService.getUser();}@GetMapping("/all")public Flux<String> getAllUsers() {return userService.getAllUsers();}
}

调用时非阻塞行为体现

  • Mono<String> 表示未来异步返回一个值;

  • Flux<String> 表示异步返回多个值;

  • 请求立即返回 Publisher,只有订阅时才开始执行(懒执行、非阻塞);

  • 它不占用线程,不会“卡死线程”等待值返回。

SpringBoot 集成示例
  • 标记 @Async 注解:

@Async 标记方法为异步执行,Spring 在线程池中运行该方法。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;@Service
public class AsyncService {@Asyncpublic CompletableFuture<String> doAsyncTask() {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return CompletableFuture.completedFuture("Task completed");}
}
  • 启用异步

在主类或配置类上添加 @EnableAsync

@SpringBootApplication
@EnableAsync
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
  • 控制器调用异步方法
@RestController
public class AsyncController {@Autowiredprivate AsyncService asyncService;@GetMapping("/async")public String triggerAsync() {asyncService.doAsyncTask().thenAccept(result -> System.out.println(result));return "Task triggered";}
}
  • 自定义线程池

Spring 默认使用 SimpleAsyncTaskExecutor,不适合生产环境。推荐配置自定义线程池。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;@Configuration
public class AsyncConfig {@Bean(name = "taskExecutor")public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(2);executor.setMaxPoolSize(10);executor.setQueueCapacity(25);executor.setThreadNamePrefix("AsyncThread-");executor.initialize();return executor;}
}
  • 指定线程池:
@Async("taskExecutor")
public CompletableFuture<String> doAsyncTask() {// 异步逻辑
}
  • @Async 方法定义全局异常处理器
@Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {@Overridepublic void handleUncaughtException(Throwable ex, Method method, Object... params) {System.err.println("Async error: " + ex.getMessage());}
}
  • Spring Boot 测试:
@SpringBootTest
public class AsyncServiceTest {@Autowiredprivate AsyncService asyncService;@Testvoid testAsync() throws Exception {CompletableFuture<String> future = asyncService.doAsyncTask();assertEquals("Task completed", future.get(2, TimeUnit.SECONDS));}
}
并行调用多个服务示例

并行调用 getUsergetProfile,总耗时接近较慢的任务(~1s)。

@Service
public class UserService {@Asyncpublic CompletableFuture<User> getUser(Long id) {return CompletableFuture.supplyAsync(() -> {// 模拟远程调用try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}return new User(id, "User" + id);});}@Asyncpublic CompletableFuture<Profile> getProfile(Long id) {return CompletableFuture.supplyAsync(() -> {try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}return new Profile(id, "Profile" + id);});}
}@RestController
public class UserController {@Autowiredprivate UserService userService;@GetMapping("/user/{id}")public CompletableFuture<UserProfile> getUserProfile(@PathVariable Long id) {return userService.getUser(id).thenCombine(userService.getProfile(id),(user, profile) -> new UserProfile(user, profile));}
}
异步批量处理示例

并行处理 10 个任务,显著减少总耗时。

@Service
public class BatchService {@Asyncpublic CompletableFuture<Void> processItem(int item) {return CompletableFuture.runAsync(() -> {try {Thread.sleep(100);System.out.println("Processed item: " + item);} catch (InterruptedException e) {throw new RuntimeException(e);}});}
}@RestController
public class BatchController {@Autowiredprivate BatchService batchService;@PostMapping("/batch")public CompletableFuture<Void> processBatch() {List<CompletableFuture<Void>> futures = new ArrayList<>();for (int i = 1; i <= 10; i++) {futures.add(batchService.processItem(i));}return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));}
}
响应式 WebFlux 示例
@Service
public class ReactiveService {public Mono<String> fetchData() {return Mono.just("Data").delayElement(Duration.ofSeconds(1));}
}@RestController
public class ReactiveController {@Autowiredprivate ReactiveService reactiveService;@GetMapping("/data")public Mono<String> getData() {return reactiveService.fetchData();}
}
Spring Data JPA 集成示例

JPA 默认阻塞操作,可通过 @Async 包装异步调用。

@Repository
public interface UserRepository extends JpaRepository<User, Long> {}@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Asyncpublic CompletableFuture<User> findUser(Long id) {return CompletableFuture.supplyAsync(() -> userRepository.findById(id).orElse(null));}
}
MyBatis Plus 集成示例

MyBatis Plus 默认阻塞,可通过 @Async 或线程池异步化。

@Mapper
public interface UserMapper extends BaseMapper<User> {}@Service
public class UserService {@Autowiredprivate UserMapper userMapper;@Asyncpublic CompletableFuture<User> getUser(Long id) {return CompletableFuture.supplyAsync(() -> userMapper.selectById(id));}
}
注意事项
  • @Async 方法必须是 public 的。

  • 不能在同一类内调用 @Async 方法(因 Spring AOP 代理机制)。

  • 默认线程池由 Spring 提供,可自定义。

CompletableFuture 所有核心 API

  • supplyAsync():异步执行任务,返回值

  • runAsync():异步执行任务,无返回值

  • thenApply():接收前面任务结果并返回新结果

  • thenAccept():接收结果但无返回

  • thenRun():不接收结果也不返回,仅执行

  • thenCompose():嵌套异步任务

  • thenCombine():两个任务都完成后,合并结果

  • allOf():等多个任务全部完成

  • anyOf():任一任务完成即继续

  • exceptionally():捕获异常并处理

  • whenComplete():无论成功失败都执行

  • handle():可处理正常或异常结果

CompletableFuture<T> 用法详解

创建异步任务
supplyAsync:基本异步任务执行
CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> "Result");
runAsync:异步执行任务,无返回值
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> System.out.println("Async run"));
任务转换
thenApply(Function):转换结果,对结果加工
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "data").thenApply(data -> data.toUpperCase());System.out.println(future.get()); // DATA
thenCompose(Function):扁平化链式异步
CompletableFuture<String> composed = CompletableFuture.supplyAsync(() -> "A").thenCompose(a -> CompletableFuture.supplyAsync(() -> a + "B"));composed.thenAccept(System.out::println); // 输出 AB
thenCombine(CompletionStage, BiFunction):两个任务完成后合并结果
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> "World");cf1.thenCombine(cf2, (a, b) -> a + " " + b).thenAccept(System.out::println);
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "A");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "B");CompletableFuture<String> result = f1.thenCombine(f2, (a, b) -> a + b);
System.out.println(result.get()); // AB
消费结果
thenAccept(Consumer):消费结果
CompletableFuture.supplyAsync(() -> "Result").thenAccept(result -> System.out.println("Received: " + result));
thenRun(Runnable):继续执行下一个任务,无需前面结果
CompletableFuture.supplyAsync(() -> "X").thenRun(() -> System.out.println("Next step executed"));
异常处理
exceptionally(Function<Throwable, T>):异常处理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (true) throw new RuntimeException("Oops!");return "ok";
}).exceptionally(ex -> "Fallback: " + ex.getMessage());System.out.println(future.get());
handle(BiFunction<T, Throwable, R>):同时处理正常与异常结果
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {throw new RuntimeException("Error!");
}).handle((result, ex) -> {if (ex != null) return "Handled: " + ex.getMessage();return result;
});System.out.println(future.get());
whenComplete(BiConsumer<T, Throwable>):类似 finally
  • CompletableFuture 执行完毕后执行一个回调,无论是成功还是异常。

  • 不会改变原来的结果或异常,仅用于处理副作用(如日志)。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Final Result").whenComplete((result, ex) -> {System.out.println("Completed with: " + result);});
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (true) throw new RuntimeException("出错了");return "成功";
}).whenComplete((result, exception) -> {if (exception != null) {System.out.println("发生异常:" + exception.getMessage());} else {System.out.println("执行结果:" + result);}
});
并发组合
allOf / anyOf:组合任务
CompletableFuture<Void> all = CompletableFuture.allOf(task1, task2);
CompletableFuture<Object> any = CompletableFuture.anyOf(task1, task2);
allOf(…):等待全部任务完成

需要单独从每个任务中再 .get() 拿到结果

CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "A");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "B");CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2);
all.thenRun(() -> System.out.println("All done")).get();
CompletableFuture<String> userFuture = CompletableFuture.supplyAsync(() -> fetchUser());
CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> fetchOrder());// 两个任务都完成后执行
CompletableFuture<Void> bothDone = CompletableFuture.allOf(userFuture, orderFuture);bothDone.thenRun(() -> {try {String user = userFuture.get();String order = orderFuture.get();System.out.println("用户: " + user + ", 订单: " + order);} catch (Exception e) {e.printStackTrace();}
});
anyOf(…):任一完成即触发
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> {try { Thread.sleep(1000); } catch (InterruptedException e) {}return "fast";
});
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "slow");CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2);
System.out.println(any.get()); // 输出最快那个
超时控制
orTimeout(long timeout, TimeUnit unit):超时异常

如果在指定时间内没有完成,就抛出 TimeoutException 异常。

CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> {try { Thread.sleep(2000); } catch (Exception e) {}return "late result";
}).orTimeout(1, TimeUnit.SECONDS);try {System.out.println(f.get());
} catch (Exception e) {System.out.println("Timeout: " + e.getMessage());
}
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}return "执行完成";
}).orTimeout(2, TimeUnit.SECONDS).exceptionally(ex -> "捕获到异常:" + ex.getClass().getSimpleName());System.out.println("结果:" + future.join()); // 打印“捕获到异常:TimeoutException”
completeOnTimeout(T value, long timeout, TimeUnit unit):超时默认值

如果在指定时间内没有完成,则返回一个默认值,并完成该任务。

CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> {try { Thread.sleep(2000); } catch (Exception e) {}return "slow";
}).completeOnTimeout("timeout default", 1, TimeUnit.SECONDS);System.out.println(f.get()); // timeout default
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(3000); // 模拟耗时任务} catch (InterruptedException e) {e.printStackTrace();}return "正常返回结果";
}).completeOnTimeout("超时默认值", 2, TimeUnit.SECONDS);System.out.println("最终结果:" + future.join()); // 会打印“超时默认值”
自定义线程池
ExecutorService pool = Executors.newFixedThreadPool(2);CompletableFuture<String> f = CompletableFuture.supplyAsync(() -> "pooled", pool);
System.out.println(f.get());
pool.shutdown();
异步任务 + 消费结果
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "hello").thenAccept(result -> System.out.println("结果是:" + result));
异步任务 + 转换结果(链式调用)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "5").thenApply(Integer::parseInt).thenApply(num -> num * 2).thenApply(Object::toString);
异常处理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {if (true) throw new RuntimeException("出错了!");return "success";}).exceptionally(ex -> {System.out.println("异常: " + ex.getMessage());return "默认值";});
多任务并发组合(allOf / anyOf)
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "A");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "B");// 等待全部完成
CompletableFuture<Void> all = CompletableFuture.allOf(f1, f2);
all.join();System.out.println("结果:" + f1.join() + ", " + f2.join());
合并两个任务结果
CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> 100);
CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> 200);CompletableFuture<Integer> result = f1.thenCombine(f2, Integer::sum);
System.out.println(result.get()); // 输出 300
自定义线程池
ExecutorService pool = Executors.newFixedThreadPool(4);CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {return "线程池中的任务";
}, pool);System.out.println(future.get());
pool.shutdown();
链式异步处理
CompletableFuture.supplyAsync(() -> "Step 1").thenApply(s -> s + " -> Step 2").thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " -> Step 3")).thenAccept(System.out::println).exceptionally(ex -> {ex.printStackTrace();return null;});
订单处理示例
public class OrderSystem {@Async("dbExecutor")public CompletableFuture<Order> saveOrder(Order order) {// 数据库写入操作return CompletableFuture.completedFuture(order);}@Async("httpExecutor")public CompletableFuture<String> notifyLogistics(Order order) {// 调用物流APIreturn CompletableFuture.completedFuture("SUCCESS");}public void processOrder(Order order) {CompletableFuture<Order> saveFuture = saveOrder(order);saveFuture.thenCompose(savedOrder -> notifyLogistics(savedOrder)).exceptionally(ex -> {log.error("物流通知失败", ex);return "FALLBACK";});}
}
总结图谱
CompletableFuture
├─ 创建任务
│  ├─ runAsync() -> 无返回值
│  └─ supplyAsync() -> 有返回值
├─ 处理结果
│  ├─ thenApply() -> 转换
│  ├─ thenAccept() -> 消费
│  ├─ thenRun() -> 执行新任务
│  ├─ thenCombine() -> 合并结果
│  └─ thenCompose() -> 链式调用
├─ 异常处理
│  ├─ exceptionally()
│  ├─ handle()
│  └─ whenComplete()
├─ 组合任务
│  ├─ allOf()
│  └─ anyOf()
└─ 超时控制├─ orTimeout()└─ completeOnTimeout()

什么场景适合用 Java 异步(@Async / CompletableFuture)?

场景是否适合异步?
调用多个远程服务并行✅ 很适合
复杂 CPU 运算耗时任务✅ 可以放到异步线程池
简单业务逻辑、数据库操作❌ 不建议,同步更可控
非主流程的日志、打点操作✅ 合适异步处理

Java 和 .NET 异步处理对比

并行调用两个服务,提高响应速度

Spring Boot 示例(@Async + CompletableFuture)

项目结构

└── src└── main├── java│   ├── demo│   │   ├── controller│   │   │   └── AggregateController.java│   │   ├── service│   │   │   ├── RemoteService.java│   │   │   └── RemoteServiceImpl.java│   │   └── DemoApplication.java

RemoteService.java

public interface RemoteService {@AsyncCompletableFuture<String> getUserInfo();@AsyncCompletableFuture<String> getAccountInfo();
}

RemoteServiceImpl.java

@Service
public class RemoteServiceImpl implements RemoteService {@Overridepublic CompletableFuture<String> getUserInfo() {try {Thread.sleep(2000); // 模拟耗时} catch (InterruptedException e) {throw new RuntimeException(e);}return CompletableFuture.completedFuture("UserInfo");}@Overridepublic CompletableFuture<String> getAccountInfo() {try {Thread.sleep(3000); // 模拟耗时} catch (InterruptedException e) {throw new RuntimeException(e);}return CompletableFuture.completedFuture("AccountInfo");}
}

AggregateController.java

@RestController
@RequestMapping("/api")
public class AggregateController {@Autowiredprivate RemoteService remoteService;@GetMapping("/aggregate")public ResponseEntity<String> aggregate() throws Exception {CompletableFuture<String> userFuture = remoteService.getUserInfo();CompletableFuture<String> accountFuture = remoteService.getAccountInfo();// 等待所有完成CompletableFuture.allOf(userFuture, accountFuture).join();// 获取结果String result = userFuture.get() + " + " + accountFuture.get();return ResponseEntity.ok(result);}
}

DemoApplication.java

@SpringBootApplication
@EnableAsync
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
.NET 示例(async/await)

项目结构

└── Controllers└── AggregateController.cs
└── Services└── IRemoteService.cs└── RemoteService.cs

IRemoteService.cs

public interface IRemoteService {Task<string> GetUserInfoAsync();Task<string> GetAccountInfoAsync();
}

RemoteService.cs

public class RemoteService : IRemoteService {public async Task<string> GetUserInfoAsync() {await Task.Delay(2000); // 模拟耗时return "UserInfo";}public async Task<string> GetAccountInfoAsync() {await Task.Delay(3000); // 模拟耗时return "AccountInfo";}
}

AggregateController.cs

[ApiController]
[Route("api/[controller]")]
public class AggregateController : ControllerBase {private readonly IRemoteService _remoteService;public AggregateController(IRemoteService remoteService) {_remoteService = remoteService;}[HttpGet("aggregate")]public async Task<IActionResult> Aggregate() {var userTask = _remoteService.GetUserInfoAsync();var accountTask = _remoteService.GetAccountInfoAsync();await Task.WhenAll(userTask, accountTask);var result = $"{userTask.Result} + {accountTask.Result}";return Ok(result);}
}
Java vs .NET 异步用法对比总结
方面Java(Spring Boot).NET Core(ASP.NET)
异步声明方式@Async + CompletableFutureasync/await
返回值类型CompletableFuture<T>Task<T>
等待多个任务CompletableFuture.allOf()Task.WhenAll()
是否阻塞.get() 会阻塞,链式不阻塞await 非阻塞
简洁性稍复杂(需要注解和线程池配置)极简、天然异步支持

相关文章:

Java 原生异步编程与Spring 异步编程 详解

简介 Java 异步编程是现代高性能应用开发的核心技术之一&#xff0c;它允许程序在执行耗时操作&#xff08;如网络请求、文件 IO&#xff09;时不必阻塞主线程&#xff0c;从而提高系统吞吐量和响应性。 异步 vs 同步 同步&#xff1a;任务按顺序执行&#xff0c;后续任务需…...

AUTOSAR图解==>AUTOSAR_TR_HWTestManagementIntegrationGuide

AUTOSAR硬件测试管理集成指南 启动和关闭阶段硬件测试管理的规范与集成 目录 文档概述 1.1 文档范围 1.2 局限性目标与动机 2.1 目标 2.2 动机 2.3 用例约束与假设缩略语与术语相关文档HTMSS AUTOSAR集成方法HTMSS功能描述AUTOSAR架构解决方案 8.1 HTMSS系统架构 8.2 HTMSS启动…...

Day22 Kaggle泰坦尼克号训练实战

​ 作业 自行学习参考如何使用kaggle平台&#xff0c;写下使用注意点&#xff0c;并对下述比赛提交代码 kaggle泰坦里克号人员生还预测 一、流程 思路概述 数据加载 &#xff1a;读取泰坦尼克号的训练集和测试集。数据预处理 &#xff1a;处理缺失值、对分类变量进行编码、…...

基于大核感知与非膨胀卷积的SPPF改进—融合UniRepLK的YOLOv8目标检测创新架构

在当前目标检测领域中&#xff0c;YOLO系列模型因其优异的速度-精度平衡能力而被广泛部署于工业界与科研场景。YOLOv8作为该系列的最新版本&#xff0c;在主干网络与特征金字塔结构上进行了多项优化&#xff0c;进一步提升了其实时性与鲁棒性。然而&#xff0c;其核心组件—SPP…...

[Linux]从零开始的STM32MP157 Busybox根文件系统构建

一、前言 在上一篇教程中&#xff0c;已经教了大家如何使用Buildroot构建根文件系统&#xff0c;并且在最后我们已经完整的构建了一个可以运行的根文件系统。但是&#xff0c;Buildroot的集成度太高了&#xff0c;不利于小白理解根文件系统&#xff0c;所以本次教程&#xff0c…...

C++ RAII机制

RAII&#xff08;Resource Acquisition Is Initialization&#xff09;是一种编程范式&#xff0c;核心思想是&#xff1a;资源的生命周期与对象绑定——对象创建时获取资源&#xff0c;对象销毁时自动释放资源。这种机制通过构造函数和析构函数的配对执行&#xff0c;确保资源…...

spring中的@Value注解详解

一、核心功能与作用 Value是Spring框架中用于动态注入属性值的注解&#xff0c;支持从配置文件、环境变量、SpEL表达式等来源注入数据&#xff0c;实现代码与配置的解耦。 注入类型覆盖广泛 基本类型&#xff1a;字符串、数值&#xff08;int/double&#xff09;、布尔值等。 …...

模型欠拟合是什么?

模型的欠拟合:全面解析 一、定义与核心概念 欠拟合(Underfitting)是指模型在训练数据、验证数据和测试数据上均表现不佳的现象。其本质是模型过于简单或学习能力不足,无法捕捉数据中的潜在规律和复杂关系,导致泛化能力差。例如,用线性模型拟合非线性数据时,模型无法描…...

IC ATE集成电路测试学习——电流测试的原理和方法

电流测试 我们可以通过电流来判断芯片的工作状态时&#xff0c;首先先了解下芯片的电流是如何产生的。 静态电流 理论上&#xff0c;CMOS结构的芯片静态时几乎不耗电 CMOS基本结构&#xff1a;Pmos Nmos 串联当逻辑电平稳定时&#xff1a; ➜ 要么Pmos导通&#xff0c;Nmo…...

Wordpress头像无法加载太慢问题解决方式

Wordpress头像无法加载太慢问题解决方式 1、找到我们当前使用的主题目录中找到functions.php文件在文件最后面添加以下代码 if ( ! function_exists( get_cravatar_url ) ) {/***替换Gravatar头像为Cravatar头像** param string $url** return string*/function get_cravatar…...

《大模型微调实战:Llama 3.0全参数优化指南》

全参数微调&#xff08;Full Parameter Fine-Tuning&#xff09;是推动大模型适应垂直领域任务的核心技术&#xff0c;尤其对于Llama 3.0这类千亿级参数模型而言&#xff0c;其性能优化与场景适配能力直接决定了实际应用价值。然而&#xff0c;全参数微调面临计算成本高、内存占…...

ActiveMQ 生产环境问题排查与调优指南(二)

五、调优策略与实践 5.1 JVM 调优 JVM 调优对于提升 ActiveMQ 性能至关重要&#xff0c;合理的 JVM 配置可以使 ActiveMQ 更高效地利用系统资源&#xff0c;减少性能瓶颈。 设置合理的堆内存大小是 JVM 调优的关键步骤。堆内存是 JVM 中用于存储对象实例的区域&#xff0c;其…...

AugmentCode 非常昂贵的新定价

AugmentCode 现在的价格比 Cursor 和 Windsurf 的总和还要贵。 AugmentCode 曾是我开发工作流程的常用工具。出乎意料的是,他们改变了定价结构,让开发者们震惊不已。 原来的30 美元月费已经增长为50 美元月费,这是一个67%的增长。 改变我看法的不仅仅是价格上涨,还有他…...

Unity 红点系统

首先明确一个&#xff0c;即红点系统的数据结构是一颗树&#xff0c;并且红点的数据结构的初始化需要放在游戏的初始化中&#xff0c;之后再是对应的红点UI侧的注册&#xff0c;对应的红点UI在销毁时需要注销对红点UI的显示回调注册&#xff0c;但是不销毁数据侧的红点注册 - …...

Python-UV多环境管理

Python-UV多环境管理 Python使用UV进行环境管理&#xff0c;系统了解UV的使用 文章目录 Python-UV多环境管理 [toc]1-学习要点2-核心知识点3-UV多环境管理4-venv和uv脚本对比1-venv环境管理2-uv环境管理3-venv对比uv 1-学习要点 1-熟悉【UV环境管理】2-熟悉【UV和Venv脚本区别…...

多空短线决策+飞云分仓操盘,两个副图指标组合操盘技术,短线更精准有效

如上图&#xff0c;两个副图指标&#xff0c;第一个【短线多空决策】&#xff0c;第二个副图指标【飞云分仓操盘】&#xff0c;指标组合使用&#xff0c;精准性和有效性更加有效。 如上图&#xff0c;两个指标组合使用&#xff0c;我们选择第二个副图指标出现红色和紫色区域的标…...

istio in action之应用弹性与容错机制

在分布式系统中&#xff0c;服务间的依赖关系就像一张错综复杂的网络&#xff0c;任何一个节点的抖动都可能引发连锁反应。这也是为什么我们需要强调弹性&#xff0c;因为在分布式系统中&#xff0c;服务之间通过网络进行通信&#xff0c;这本身就引入了无数个潜在的失败点。我…...

将PyQt5设计的程序打包成.exe文件

打包教程 因为打包的机制是会把当前的解释器的包也打包上&#xff0c;而我的环境经常会有一些较大的包&#xff0c;比如torch之类的。所以这里会创建一个单独的环境。 conda create -n image_process python3.8 激活环境 conda activate image_process 现在先安装我需要安装…...

Java原生结合MQTTX---完成心跳对话(附带源码)

简言&#xff1a;✨当Java遇上MQTT&#xff1a;打造会"隔空传话"的魔法程序✨ 导语&#xff1a;想不想让两个Java程序像哈利波特里的双面镜一样实时对话&#xff1f;今天我们将用MQTT协议EMQX&#xff0c;在Ubuntu上搭建一个魔法邮局&#xff0c;再亲手编写会传信的…...

redis数据结构-06(LRANGE、LINDEX、LSET、LREM)

列表操作&#xff1a;LRANGE、LINDEX、LSET、LREM Redis 列表不仅仅是简单的数组&#xff1b;它们是一种强大的数据结构&#xff0c;可以高效地操作有序数据。本课将深入探讨使用 Redis 列表的四个基本命令&#xff1a; LRANGE 、 LINDEX 、 LSET 和 LREM 。掌握这些命令将使您…...

4.4 os模块

os模块&#xff1a; chdir:修改工作路径 --- 文件所在位置的标识 getcwd():返回当前路径&#xff0c;如果修改了则显示修改后的路径 curdir:获取当前目录的表示形式 cpu_count():返回当前cpu的线程数 getppid(): 获取当前进程编号 getppid()&#xff1a;获取当前进程的父进…...

在 Windows 系统上选择与部署 DICOM 医学影像开发工具与库

🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C++, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C++、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle,mysql,postgresql等进行开发应用…...

MYSQL数据库集群高可用和数据监控平台(详细版)

项目说明 概述 该项目共分为2个子项目&#xff0c;由MYSQL集群高可用和数据监控平台两部分组成 MYSQL集群高可用属于云原生高级课数据库运维部分的知识 数据监控平台属于云原生拔高项目&#xff0c;旨在让学生增加知识面&#xff0c;提高项目实习经历&#xff0c;充实简历 …...

学习通刷课稳定版(美化面板+完全免费)

学习通刷 &#xff08;美化面板完全免费&#xff09; 安装教程方法一源码文件 方法二 提示结尾 安装教程 方法一 我们首先在浏览器打开脚本猫网站并获取该插件&#xff08;浏览器以Edge为例&#xff09; 脚本猫首页&#xff1a;https://scriptcat.org/zh-CN/ 第一步&#xff…...

python 实现sha加密

在Python中&#xff0c;SHA&#xff08;Secure Hash Algorithm&#xff09;是一种加密哈希函数&#xff0c;通常用于生成数据的哈希值。SHA算法是单向的&#xff0c;这意味着它只能用于加密&#xff08;生成哈希值&#xff09;&#xff0c;而不能用于解密。因此&#xff0c;SHA…...

Linux epoll 详解:概念、使用、数据结构、流程及应用

epoll是什么&#xff1f; epoll 是从 Linux 2.6 起&#xff0c;Linux内核提供的一种高性能I/O事件通知机制&#xff0c;用于解决传统 select 和 poll 在处理大量并发连接时遍历、最大数量限制、频繁拷贝数据等问题。epoll 可以用来监听多个文件描述符&#xff08;socket、管道…...

Kubernetes排错(十一):lsof命令实战场景

在Kubernetes生产环境中&#xff0c;lsof作为Linux系统的"透视眼"&#xff0c;是排查容器级疑难杂症的必备工具。本文将深入解析其在容器化场景下的高阶用法&#xff0c;助你快速定位隐藏问题。 一、基础环境准备 1. 容器内安装lsof # 临时进入容器安装&#xff0…...

Java基础语法之循环结构

循环结构 1.定义 控制一段代码重复执行多次 2.分类 2.1 for循环 2.1.1 定义 控制一段代码反复执行很多次。 2.1.2 for循环格式 for (初始化语句; 循环条件; 迭代语句) { 循环体语句(重复执行的代码); }示例 // 输出3次HelloWorld for (int i 0; i < 3; i) { System…...

冒泡排序的原理

冒泡排序是一种简单的排序算法&#xff0c;它通过重复地遍历待排序的列表&#xff0c;比较相邻的元素并交换它们的位置来实现排序。具体原理如下&#xff1a; 冒泡排序的基本思想 冒泡排序的核心思想是通过相邻元素的比较和交换&#xff0c;将较大的元素逐步“冒泡”到列表的…...

AUTOSAR图解==>AUTOSAR_TR_InteractionWithBehavioralModels

AUTOSAR与行为模型交互详解 深入解析AUTOSAR软件组件与行为模型的交互关系与转换机制 目录 引言 1.1 AUTOSAR编辑工具概述 1.2 源起与目标 1.3 术语定义需求追溯AUTOSAR中行为建模的用例 3.1 软件组件的行为建模 3.2 软件组件描述到行为模型 3.3 行为模型到软件组件描述 3.4 组…...

GO语言内存管理结构

文章目录 1、内存分区1.1、栈&#xff08;Stack&#xff09;1.2、堆&#xff08;Heap&#xff09; 2、堆内存管理结构2.1、内存分配器&#xff08;MCache → MArena → MSpan → MHeap&#xff09;2.2、大小分类&#xff08;Size Class&#xff09;2.3、分配流程 3、垃圾回收&a…...

分享一些资料供大家学习

群里收集来的&#xff0c;自己感觉还是比较经典的&#xff0c;希望大家喜欢&#xff01;&#xff01;&#xff01; 20250428 夸克网盘分享一大波经典IT架构好货20250429夸克网盘分享精品文档-管理咨询师必备的思维模型20250430夸克网盘分享清华大学DeepSeek教程又来了《文科生A…...

RAGMCP基本原理说明和相关问题解惑

一、RAG架构原理和局限性 1.1 概念解释 RAG&#xff08;Retrieval-Augmented Generation&#xff09;&#xff1a;检索增强生成&#xff0c;让大模型接受外部输入后&#xff0c;总结输出 向量数据库&#xff1a;向量数据通常是高维空间中的点&#xff0c;代表复杂的数据结构…...

PyGame游戏开发(含源码+演示视频+开结题报告+设计文档)

前言&#xff1a; 大二小学期python课上基于pygame做的一个游戏小demo&#xff0c;当时老师花了一天讲解了下python基础语法后&#xff08;也是整个大学四年唯一学习python的时间&#xff09;&#xff0c;便让我们自学网课一周然后交项目&#xff0c;所以做的非常仓促&#xff…...

Git标签

Git标签 1. 添加标签 使用 tag 命令可以给某次 commit 提交的版本打上标签&#xff0c;相当于这个 commit id 的别名&#xff0c;在实践中&#xff0c;会使用 v1.0 之类的标签提示这是正式版的第一个版本。 git tag v1.0 [commit id]缺省输入 commit id会给最新的一次提交打…...

USB学习【6】USB传输错误的处理

1.前言 我们从物理层到信号层&#xff0c;到协议层&#xff0c;他们分别在不同的层面完成不同的功能。 总结一下&#xff1a; 物理层实现了高低电平的检测。 信号层更进一步&#xff0c;通过一些方法&#xff0c;实现了二进制的传输。 协议层&#xff0c;因为可以二进制传输了…...

深入解析 Vision Transformer (ViT) 与其在计算机视觉中的应用

在近年来&#xff0c;深度学习尤其在计算机视觉领域取得了巨大的进展&#xff0c;而 Vision Transformer&#xff08;ViT&#xff09;作为一种新的视觉模型&#xff0c;它的表现甚至在许多任务中超过了传统的卷积神经网络&#xff08;CNN&#xff09;&#xff0c;如 ResNet。在…...

《Go小技巧易错点100例》第三十一篇

本期分享&#xff1a; 1.Go struct内存对齐 2.使用空结构体(struct{})节省内存 Go struct内存对齐 在计算机系统中&#xff0c;CPU 访问内存时并不是逐字节读取的&#xff0c;而是以特定大小的块&#xff08;通常为 4/8 字节&#xff09;为单位进行读取。当数据的内存地址正…...

全栈项目实战:Vue3+Node.js开发博客系统

全栈项目实战&#xff1a;Vue3Node.js开发博客系统 一、项目架构设计 1. 技术栈选型 前端技术栈&#xff1a; Vue 3 Composition APITypeScriptPinia状态管理Vue Router 4Element Plus UI组件库Vite构建工具 后端技术栈&#xff1a; Node.js (Express/Koa)MongoDB (Mong…...

查看YOLO版本的三种方法

查看YOLO版本的三种方法&#xff1a; 一、通过命令行直接查询 使用Python交互式查询&#xff1a; from ultralytics import __version__ print(__version__) # 示例输出: 11.0.5二、检查PyTorch环境兼容性 import torch, ultralytics print(f"PyTorch: {torch.__versi…...

基于Docker的Bitwarden的私有本地部署

基于Docker的Bitwarden的私有本地部署 文章目录 基于Docker的Bitwarden的私有本地部署 本文首发地址 https://h89.cn/archives/355.html bitwarden 默认连接的是国外服务器 https://bitwarden.com/ &#xff0c;连接不是很稳定&#xff0c;也没有安全感&#xff0c;所以我选择了…...

点和体素哪个好

3D 深度学习中基于体素和基于点云的方法哪种更优&#xff1f;-腾讯云开发者社区-腾讯云 https://zhuanlan.zhihu.com/p/372497398 GitHub - open-mmlab/OpenPCDet: OpenPCDet Toolbox for LiDAR-based 3D Object Detection....

C++ STL编程 vector空间预留、vector高效删除、vector数据排序、vector代码练习

vector空间预留&#xff0c;作用是避免申请每次申请内存&#xff0c;提高运行效率。 对应的接口是 vector.reverse() vector的高效删除&#xff0c;对应的代码见下&#xff0c;一个时间复杂度是n&#xff0c;一个时间复杂度是1 #include<iostream> #include<vector…...

Android架构模式推荐及分析和MVC架构模式制作一个简单的底部tab切换

目录 主流架构模式对比 适用场景 MVP‌&#xff1a;团队协作开发,需要高可测试性的项目 MVC架构模式制作一个简单的底部tab切换 &#xff08;Model-View-Controller&#xff09;结构 代码 效果 主流架构模式对比 ‌对比维度‌‌MVC‌ ‌MVP‌ ‌MVVM‌ ‌MVI‌ ‌学习…...

【PVE】ProxmoxVE8虚拟机,存储管理(host磁盘扩容,qcow2/vmdk导入vm,vm磁盘导出与迁移等)

【PVE】ProxmoxVE8虚拟机&#xff0c;存储管理&#xff08;host磁盘扩容&#xff0c;qcow2/vmdk导入vm&#xff0c;vm磁盘导出与迁移等&#xff09; 文章目录 1、host 磁盘扩容2、qcow2/vmdk导入vm3、vm 磁盘导出与迁移 1、host 磁盘扩容 如何给host扩容磁盘&#xff0c;如增加…...

【JEECG 组件扩展】JSwitch开关组件扩展单个多选框样式

功能说明&#xff1a; 基于JeecgBoot开源框架&#xff0c;JSwitch开关组件扩展&#xff0c;支持单个多选样式。 效果展示&#xff1a; 使用示例&#xff1a; {field: JSwitch,component: JSwitch,label: JSwitch,},{field: JSwitchCheckBox,component: JSwitch,label: JSwitch…...

卷积神经网络-从零开始构建一个卷积神经网络

目录 一、什么是卷积神经网络CNN 1.1、核心概念 1.2、卷积层 二、什么是卷积计算 2.1、卷积计算的例子: 2.2、点积 2.3、卷积与点积的关系 2.4、Padding(填充) 2.4.1、Padding的主要作用 1、控制输出特征图尺寸 2、保留边缘信息 3. 支持深层网络训练 2.4.2、Str…...

Linux 常用命令集合

以下是一份 Linux 常用命令集合&#xff0c;涵盖文件操作、系统管理、网络管理、权限管理、进程管理等常见任务&#xff0c;并附上代码示例&#xff1a; 1. 文件与目录操作 命令作用示例ls列出目录内容ls -l&#xff08;详细列表&#xff09; ls -a&#xff08;显示隐藏文件&a…...

STM32f103 标准库 零基础学习之按键点灯(不涉及中断)

注意&#xff0c;此次代码不涉及中断&#xff0c;不涉及中断&#xff0c;不涉及中断 目录 1.初始化LED 2.初始化按键 3.粗略的延时函数 4.判断引脚电平 5.通过异或反转电平 开始 │ ├── 初始化LED&#xff08;GPIOA Pin1 推挽输出&#xff09; ├── 初始化按键&…...

【c++】【数据结构】二叉搜索树详解

目录 二叉搜索树的定义二叉搜索树的模拟实现查找函数循环版递归版 插入函数循环版递归版 删除函数循环版递归版 二叉搜索树的定义 二叉搜索树是一种特别的二叉树&#xff0c;是二叉树的搜索特化版。学过排序的都知道&#xff0c;在数组有序的情况下二分查找可以以极高的频率找…...