CompletableFuture的用法如下
executor 对象是我自定义的一个线程池,其具体代码如下,我通过@Autowired和@Qualifier注解通过name别名注入的方式注入
@Configuration
public class AsyncConfiguration {
@Autowired
private ThreadExecutorPoolLogProperties logProperties;
@Autowired
private ThreadExecutorPoolTaskProperties taskProperties;
@Bean("taskExecutor")
public Executor taskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(taskProperties.getCorePoolSize());
// 设置最大线程数
executor.setMaxPoolSize(taskProperties.getMaxPoolSize());
// 设置队列容量
executor.setQueueCapacity(taskProperties.getQueueCapacity());
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(taskProperties.getKeepAliveSeconds());
//等待时间 (默认为0,此时立即停止),并没等待xx秒后强制停止
executor.setAwaitTerminationSeconds(taskProperties.getAwaitTerminationSeconds());
// 设置默认线程名称
executor.setThreadNamePrefix("task-");
/** 设置拒绝策略 为 调用者运行策略(即 使用当前线程同同步处理)
* CallerRunsPolicy(调用者运行策略)
* AbortPolicy(中止策略)
* DiscardPolicy(丢弃策略)
* DiscardOldestPolicy(弃老策略)
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
1、异步执行任务(无返回值)
@Autowired
@Qualifier("taskExecutor")
private Executor executor;
//异步执行任务(无返回值)
@GetMapping("/test1")
public void testMethod(){
log.info("我是主线程1");
CompletableFuture.runAsync(()->{
try {
Thread.sleep(5000l);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("我是异步执行");
},executor);
log.info("我是主线程2");
}
控制台打印结果
[:10.79.8.110:7001] [4d517ac72d623da8,] 2025-10-14 10:45:10.850 INFO 68788 [http-nio-7001-exec-6] com.xxxx.TestController 我是主线程1
[:10.79.8.110:7001] [4d517ac72d623da8,] 2025-10-14 10:45:10.851 INFO 68788 [http-nio-7001-exec-6] com.xxxx.TestController 我是主线程2
[:10.79.8.110:7001] [4d517ac72d623da8,] 2025-10-14 10:45:15.854 INFO 68788 [task-3] com.xxxx.TestController 我是异步执行
2、异步执行任务(有返回值)
具体代码如下:
@GetMapping("/test2")
public void testMethod2() throws ExecutionException, InterruptedException {
log.info("我是主线程1");
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000l);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("我是异步执行");
return "我是异步返回值结果";
}, executor);
log.info("我是主线程2");
//future.get()有阻塞作用
String result = future.get();
log.info("异步返回值结果:{}",result);
}
控制台打印结果如下:
[:10.79.8.110:7001] [156778a6694bf28d,] 2025-10-14 10:49:54.556 INFO 68788 [http-nio-7001-exec-9] com.xxxx.TestController 我是主线程1
[:10.79.8.110:7001] [156778a6694bf28d,] 2025-10-14 10:49:54.559 INFO 68788 [http-nio-7001-exec-9] com.xxxx.TestController 我是主线程2
[:10.79.8.110:7001] [156778a6694bf28d,] 2025-10-14 10:49:59.559 INFO 68788 [task-4] com.xxxx.TestController 我是异步执行
[:10.79.8.110:7001] [156778a6694bf28d,] 2025-10-14 10:49:59.560 INFO 68788 [http-nio-7001-exec-9] com.xxxx.TestController 异步返回值结果:我是异步返回值结果
从控制台可以看出,future.get()方法有阻塞作用。
3、链式调用:thenApply() 处理结果
//链式调用:thenApply() 处理结果
@GetMapping("/test3")
public void testMethod3() throws ExecutionException, InterruptedException {
log.info("我是主线程1");
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Hello";
}, executor)
.thenApply(s -> s+"World") //s是上一个任务的结果
.thenApply(s-> s+"China");//继续处理
String result = future.get();
log.info("异步返回值结果:{}",result);
}
控制台结果:
[:10.79.8.110:7001] [aacf023b4640ada6,] 2025-10-14 10:57:06.321 INFO 64564 [http-nio-7001-exec-2] com.xxxx.TestController 我是主线程1
[:10.79.8.110:7001] [aacf023b4640ada6,] 2025-10-14 10:57:06.327 INFO 64564 [http-nio-7001-exec-2] com.xxxx.TestController 异步返回值结果:HelloWorldChina
4、消费结果:thenAccept() 不返回新结果。简单说,thenAccept() 就像一个 “终结者” 操作 —— 它负责处理结果,但不会把处理后的内容传递给下一个步骤,适合作为异步流程的收尾操作(如日志记录、结果通知等)。
//消费结果:thenAccept() 不返回新结果
@GetMapping("/test4")
public void testMethod4() throws ExecutionException, InterruptedException {
log.info("我是主线程1");
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
return "计算结果: " + (100 + 200);
}, executor)
.thenAccept(s -> {
log.info("最终数据结果为:{}",s); //这一步只输出结果,不会给future.get();方法有返回值
});
future.get();
log.info("我是主线程2");
}
控制台打印:
[:10.79.8.110:7001] [e4cb0c4a8aa7d767,] 2025-10-14 11:09:43.635 INFO 48552 [http-nio-7001-exec-2] com.xxxx.TestController 我是主线程1
[:10.79.8.110:7001] [e4cb0c4a8aa7d767,] 2025-10-14 11:09:43.664 INFO 48552 [task-1] com.xxxx.TestController 最终数据结果为:计算结果: 300
[:10.79.8.110:7001] [e4cb0c4a8aa7d767,] 2025-10-14 11:09:43.665 INFO 48552 [http-nio-7001-exec-2] com.xxxx.TestController 我是主线程2
5、组合两个独立任务:thenCombine()
代码如下:
@GetMapping("/test5")
public void testMethod5() throws Exception {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(
() -> {
try {
Thread.sleep(7000l);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("我是异步线程1");
return 10;
}, executor);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(
() -> {
try {
Thread.sleep(5000l);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("我是异步线程2");
return 20;
}, executor);
CompletableFuture<Integer> result = future1.thenCombine(future2, (a, b) -> a + b);
log.info("我是组合结果:{}", result.get());
}
打印结果如下:
[:10.79.8.110:7001] [2a219e11c4e4e246,] 2025-10-14 11:20:18.383 INFO 71148 [task-2] com.xxxx.TestController 我是异步线程2
[:10.79.8.110:7001] [2a219e11c4e4e246,] 2025-10-14 11:20:20.383 INFO 71148 [task-1] com.xxxx.TestController 我是异步线程1
[:10.79.8.110:7001] [2a219e11c4e4e246,] 2025-10-14 11:20:20.384 INFO 71148 [http-nio-7001-exec-2] com.xxxx.TestController 我是组合结果:30
6、等待所有任务完成 allOf方法
代码 如下:
//等待所有任务完成 allOf方法
@GetMapping("/test6")
public void testMethod6() throws Exception {
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(5000l);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("我是异步方法1");
}, executor);
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(3000l);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("我是异步方法2");
}, executor);
CompletableFuture<Void> result = CompletableFuture.allOf(future1, future2);
result.get();
log.info("所有任务都完成");
}
打印结果如下:
[10.79.8.110:7001] [2d8187cf09af6ce1,] 2025-10-14 11:38:28.203 INFO 60896 [task-2] com.xxxx.TestController 我是异步方法2
[10.79.8.110:7001] [2d8187cf09af6ce1,] 2025-10-14 11:38:30.211 INFO 60896 [task-1] com.xxxx.TestController 我是异步方法1
[10.79.8.110:7001] [2d8187cf09af6ce1,] 2025-10-14 11:38:30.213 INFO 60896 [http-nio-7001-exec-1] com.xxxx.TestController 所有任务都完成
7、处理异常:exceptionally()
代码如下:
//处理异常:exceptionally()
@GetMapping("/test7")
public void testMethod7() throws Exception {
CompletableFuture<String> future = CompletableFuture.supplyAsync(
() -> {
if (true) {
throw new RuntimeException("任务执行失败!");
}
return "正常结果";
},executor).exceptionally(ex -> {
log.error("捕获异常:{}",ex.getMessage());
return "默认结果"; // 异常时返回默认值
});
log.info("最终输出结果:{}",future.get());
}
输出结果如下
[:10.79.8.110:7001] [c12586e9a2cfe98d,] 2025-10-14 11:39:09.297 ERROR 60896 [task-3] com.xxxx.TestController 捕获异常:java.lang.RuntimeException: 任务执行失败!
[:10.79.8.110:7001] [c12586e9a2cfe98d,] 2025-10-14 11:39:09.299 INFO 60896 [http-nio-7001-exec-3] com.xxxx.TestController 最终输出结果:默认结果
1207

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



