CompletableFuture-获得结果和触发计算

本文详细探讨了Java中的CompletableFuture类,如何使用它来异步获取结果并触发计算。通过实例,展示了CompletableFuture的thenApply、thenAccept和thenRun等方法的用法,以及如何优雅地处理异常情况。同时,对比了Java异步编程与Python协程的差异,帮助开发者更好地理解和应用并发编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.nanjing.gulimall.zhouyimo.test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author zhou
 */
public class CompletableFutureAPIDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() ->{
            //暂停几秒钟线程
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "ABC";
        });
        //System.out.println(completableFuture.get());//ABC

        //和get一样的作用,只是不需要抛出异常
        //System.out.println(completableFuture.join());//ABC

        //只愿意等2秒
        //System.out.println(completableFuture.get(2L,TimeUnit.SECONDS));//抛出异常

        //计算完成就返回正常值,否则返回备胎值(传入的参数),立即获取结果不阻塞
        //System.out.println(completableFuture.getNow("XXX"));//XXX

        //是否打断get方法立即返回括号值
        System.out.println(completableFuture.complete("YYY")+"---"+completableFuture.get());//true---YYY
    }
}

### CompletableFuture 同步与异步操作 #### 同步调用 在同步模式下,`CompletableFuture`的行为类似于传统阻塞式的 `Future` 对象。一旦发起请求,则会立即进入等待状态直到获取结果为止。这通常意味着主线程会被挂起直至子任务结束。 例如,在下面的例子中展示了如何创建并同步地获得一个简单的字符串返回值: ```java public class SyncExample { public static void main(String[] args) throws Exception { // 创建一个新的 completable future 实例,并指定它的完成逻辑 CompletableFuture<String> cf = new CompletableFuture<>(); // 显式设置该实例的结果为 "Hello" cf.complete("Hello"); // 阻塞当前线程直到得到计算后的最终结果 System.out.println(cf.join()); } } ``` 此段代码将输出 `"Hello"` 并且整个过程是完全同步的,因为 `join()` 方法会使程序暂停执行,直到 `cf` 被标记为已完成并且可以访问其内部存储的数据[^1]。 #### 异步调用 相比之下,异步方式允许应用程序继续运行其他工作而无需等待特定的任务完成。对于长时间运行的操作尤其有用,因为它不会占用宝贵的资源如 CPU 或内存来保持休眠态。 考虑这样一个场景:有三个独立的服务端点分别负责不同的数据检索任务 (`getSomething1`, `getSomething2`, `getSomething3`) 。如果采用常规顺序调用的方式,那么总的延迟将是各个单独 API 请求所花费时间相加起来的结果。然而借助于 `CompletableFuture.allOf(...)` 可以让这些查询几乎同时发生,从而大大减少了整体耗时。 这里有一个具体的例子说明了这一点: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; class AsyncExample { private static String getSomething(int i){ try{ Thread.sleep(3000); // Simulate delay. } catch (InterruptedException e){} return "Result "+i; } public static void main(String[] args)throws InterruptedException, ExecutionException { long start=System.currentTimeMillis(); // Start all three asynchronous operations at once. CompletableFuture<String>[] futures=new CompletableFuture[]{ CompletableFuture.supplyAsync(() -> getSomething(1)), CompletableFuture.supplyAsync(() -> getSomething(2)), CompletableFuture.supplyAsync(() -> getSomething(3)) }; // Wait until they are ALL done before proceeding further down the line... CompletableFuture<Void> combinedFutures=CompletableFuture.allOf(futures); combinedFutures.get(); for(var f :futures){ System.out.println(f.get()); } System.out.printf("Total time taken: %d ms\n", System.currentTimeMillis()-start); } } ``` 上述代码片段里定义了一个模拟网络请求延时的方法 `getSomething(i)` ,每次都会休眠三秒钟再给出相应的回应串。接着启动三个这样的后台作业并通过 `allOf` 将它们组合成单一的整体以便统一管理。最后打印出所有已收到的信息以及总历时长度。理论上讲这段脚本应该能在大约三千毫秒内跑完而不是九千毫秒[^4]。 #### 主要差异总结 | 特征 | **同步** | **异步** | --- | --- | --- | 执行流程控制 | 程序按部就班依次往下走,每一步都得等到前一阶段彻底结束后才能开始下一步骤 | 多个指令可能交错重叠着被执行,只要条件满足即可立刻触发下一个环节 | | 性能影响 | 占用了更多的CPU周期上下文切换开销,特别是在面对大量I/O密集型活动的时候表现尤为明显 | 减少了不必要的等待时间资源浪费,提高了系统的吞吐量 | | 编码难度 | 更容易理解调试,适合初学者入门学习 | 设计上更为复杂些,需要开发者具备一定的并发编程经验 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZHOU_VIP

您的鼓励将是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值