Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >并发设计模式实战系列(15):Future/Promise

并发设计模式实战系列(15):Future/Promise

作者头像
摘星.
发布于 2025-05-20 07:06:14
发布于 2025-05-20 07:06:14
11100
代码可运行
举报
文章被收录于专栏:博客专享博客专享
运行总次数:0
代码可运行

🌟 大家好,我是摘星! 🌟

今天为大家带来的是并发设计模式实战系列,第十五章Future/Promise,废话不多说直接开始~

一、核心原理深度拆解

1. 异步计算双阶段模型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Task      │───>│   Future    │───>│   Callback  │
│ Submission  │<───│  (Promise)<───│  Execution  │
└─────────────┘    └─────────────┘    └─────────────┘
  • 提交阶段:主线程提交任务后立即返回Future占位符
  • 计算阶段:工作线程异步执行计算,通过Promise设置结果
  • 回调阶段:结果就绪后触发回调(观察者模式)
2. 状态机流转
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public interface Future<V> {
    boolean isDone();      // 完成状态(成功/失败/取消)
    V get() throws...;     // 阻塞获取结果
    void addCallback(...); // 回调注册
}

二、生活化类比:快递柜取件

系统组件

现实类比

核心行为

Future

快递柜取件码

凭码查询包裹是否到达

Promise

快递员存件操作

实际将包裹放入柜中并更新状态

Callback

短信通知服务

包裹入柜后自动发送取件提醒

  • 异步流程:下单→获得取件码(Future)→快递员送货(异步计算)→短信通知(Callback)

三、Java代码实现(生产级Demo)

1. 完整可运行代码
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import java.util.concurrent.*;
import java.util.function.Consumer;

public class FuturePromiseDemo {

    // 1. 自定义Promise实现
    static class MyPromise<V> implements Future<V>, Runnable {
        private volatile V result;
        private volatile Throwable error;
        private volatile boolean isDone;
        private final CountDownLatch latch = new CountDownLatch(1);
        private final List<Consumer<V>> callbacks = new CopyOnWriteArrayList<>();

        // 提交任务时执行的方法
        @Override
        public void run() {
            try {
                // 模拟耗时计算
                Thread.sleep(1000);
                setResult((V) "计算结果"); // 实际业务逻辑替换此处
            } catch (Exception e) {
                setError(e);
            }
        }

        // Promise核心方法:设置结果
        public void setResult(V result) {
            this.result = result;
            this.isDone = true;
            latch.countDown();
            notifyCallbacks();
        }

        // Promise核心方法:设置异常
        public void setError(Throwable error) {
            this.error = error;
            this.isDone = true;
            latch.countDown();
        }

        private void notifyCallbacks() {
            callbacks.forEach(cb -> cb.accept(result));
        }

        // Future实现方法
        @Override
        public V get() throws InterruptedException, ExecutionException {
            latch.await();
            if (error != null) throw new ExecutionException(error);
            return result;
        }

        @Override
        public boolean isDone() {
            return isDone;
        }

        // 注册回调(非JUC标准方法)
        public void addCallback(Consumer<V> callback) {
            if (isDone) {
                callback.accept(result);
            } else {
                callbacks.add(callback);
            }
        }
    }

    // 2. 使用示例
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newCachedThreadPool();
        
        // 创建Promise并提交任务
        MyPromise<String> promise = new MyPromise<>();
        executor.submit(promise);

        // 注册回调
        promise.addCallback(result -> 
            System.out.println("[回调] 异步结果: " + result));

        // 同步阻塞获取
        System.out.println("[主线程] 立即返回,继续其他工作...");
        System.out.println("最终结果: " + promise.get());

        executor.shutdown();
    }
}
2. 关键机制说明
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 1. 状态同步控制
private volatile boolean isDone;  // 保证可见性
private final CountDownLatch latch; // 实现阻塞等待

// 2. 线程安全回调列表
private final List<Consumer<V>> callbacks = new CopyOnWriteArrayList<>();

// 3. 异常处理流程
public void setError(Throwable error) {
    this.error = error;
    this.isDone = true;
    latch.countDown(); // 唤醒所有等待线程
}

四、横向对比表格

1. 异步模式对比

模式

核心特点

适用场景

Java实现类

Future

阻塞式获取结果

简单异步任务

FutureTask

CompletableFuture

链式调用+组合操作

复杂异步流水线

CompletableFuture

Promise

可写的结果容器

跨线程结果传递

需自行实现

Callback

事件驱动无阻塞

高并发IO

Netty的ChannelFuture

2. 回调注册方式对比

方法

触发时机

线程安全性

链式支持

addCallback

结果就绪后立即执行

需自行保证

不支持

thenApply

前序阶段完成后触发

内置线程池控制

支持

whenComplete

无论成功失败都执行

可能在不同线程执行

支持


五、高级应用技巧

1. 组合多个异步任务
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CompletableFuture<String> query1 = queryDatabase("sql1");
CompletableFuture<String> query2 = queryDatabase("sql2");

// 并行执行后合并结果
CompletableFuture<String> merged = query1.thenCombineAsync(query2, 
    (r1, r2) -> r1 + "|" + r2,
    ForkJoinPool.commonPool());
2. 超时控制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Future<String> future = executor.submit(task);
try {
    String result = future.get(2, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    future.cancel(true); // 中断任务执行
}
3. 回调线程控制
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
promise.addCallback(result -> {
    // 指定回调执行线程池
    ForkJoinPool.commonPool().execute(() -> processResult(result));
});

通过这种 原理+实现+对比 的立体解析,可以掌握:

  1. Future/Promise的双阶段异步本质
  2. 如何实现生产级的Promise容器
  3. 不同异步模式的适用场景选择
  4. 复杂场景下的组合使用技巧

六、源码级实现剖析(接五)

1. JDK FutureTask 核心逻辑
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 状态机定义(OpenJDK 17)
private volatile int state;
static final int NEW          = 0; // 初始化状态
static final int COMPLETING   = 1; // 临时状态
static final int NORMAL       = 2; // 正常完成
static final int EXCEPTIONAL  = 3; // 异常完成
static final int CANCELLED    = 4; // 已取消
static final int INTERRUPTING = 5; // 中断中
static final int INTERRUPTED  = 6; // 已中断

// 结果存储设计
private Object outcome; // 非volatile,依赖状态可见性保证
2. CompletableFuture 回调链实现
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 回调节点结构(简化版)
static final class UniCompletion<T,V> extends Completion {
    Executor executor;         // 执行线程池
    CompletableFuture<V> dep;   // 依赖的前序Future
    BiFunction<? super T,? super Throwable,? extends V> fn; // 回调函数

    void tryFire(int mode) {    // 触发回调执行
        if (dep != null && 
            compareAndSetState(0, 1)) { // CAS保证线程安全
            fn.apply(src, ex);  // 实际执行用户回调
        }
    }
}

七、生产环境最佳实践

1. 异常处理模板
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CompletableFuture.supplyAsync(() -> {
        // 业务逻辑
        return doSomething();
    })
    .exceptionally(ex -> {      // 捕获所有异常
        log.error("任务失败", ex);
        return defaultValue;    // 提供降级值
    })
    .thenAccept(result -> {     // 只处理成功情况
        updateUI(result); 
    });
2. 资源清理策略
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
try {
    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        // 使用try-with-resources确保资源释放
        try (Connection conn = getConnection()) {
            process(conn);
        }
    }, executor);
    
    future.whenComplete((r, ex) -> {
        if (ex != null) {
            cleanupTempFiles(); // 失败时清理临时文件
        }
    });
} finally {
    executor.shutdown(); // 确保线程池关闭
}
3. 性能监控指标
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 监控Future完成时长
Timer.Sample sample = Timer.start();
future.whenComplete((r, ex) -> {
    sample.stop(registry.timer("async.task.time"));
});

// 监控队列积压
ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;
metrics.gauge("task.queue.size", pool.getQueue()::size);

八、与其他模式的协作

1. 结合发布-订阅模式
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
EventBus bus = new EventBus();
CompletableFuture.supplyAsync(() -> fetchData())
    .thenAccept(data -> {
        bus.post(new DataReadyEvent(data)); // 异步事件通知
    });

// 订阅方处理
@Subscribe
void handleDataReady(DataReadyEvent event) {
    // 处理已完成的数据
}
2. 与反应式编程整合
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// CompletableFuture -> Mono
Mono.fromFuture(() -> {
    return CompletableFuture.supplyAsync(() -> {
        return reactiveDao.query();
    });
}).subscribeOn(Schedulers.boundedElastic())
  .subscribe(System.out::println);

// Mono -> CompletableFuture
reactorMono.toFuture().thenApply(...);

九、各语言实现对比

语言

核心实现类

特色功能

典型使用场景

Java

CompletableFuture

链式组合、CompletionStage

服务端异步编排

C#

Task

async/await语法糖

UI线程非阻塞调用

JavaScript

Promise

then/catch链式调用

前端API请求

Python

asyncio.Future

协程集成

爬虫/高并发IO

Go

chan

通道原生支持

高并发微服务


十、常见陷阱与解决方案

1. 回调地狱问题

反模式

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
future.thenApply(r1 -> {
    future2.thenApply(r2 -> {
        future3.thenApply(r3 -> {  // 嵌套层次过深
            return r1 + r2 + r3;
        });
    });
});

解决方案

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 使用组合式编程
CompletableFuture.allOf(future1, future2, future3)
    .thenApply(v -> {
        return future1.join() + 
               future2.join() + 
               future3.join();
    });
2. 线程泄漏场景

问题代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ExecutorService executor = Executors.newFixedThreadPool(5);
CompletableFuture.runAsync(() -> {
    while (true) {  // 无限循环任务
        process();
    }
}, executor);  // 线程永远无法回收

正确做法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 使用守护线程或超时控制
ExecutorService executor = Executors.newFixedThreadPool(5, r -> {
    Thread t = new Thread(r);
    t.setDaemon(true);  // 设置为守护线程
    return t;
});
3. 上下文丢失问题

问题现象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SecurityContext ctx = getContext();
CompletableFuture.runAsync(() -> {
    // 此处无法获取原始上下文
    doPrivilegedAction(); 
}, executor);

解决方案

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 使用ContextPropagator
ExecutorService wrappedExecutor = ContextPropagator.wrap(executor);
CompletableFuture.runAsync(() -> {
    // 可以获取原始上下文
    doPrivilegedAction();
}, wrappedExecutor);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
并行设计模式--Future、Callback、Promise
在异步处理过程中需要大量使用Future,Callback,Promise,深入学习分析这几种异步编程的原理。
屈定
2018/09/27
4.9K0
JUC并发—13.Future模式和异步编程简介
Callable接口需要与Future和ExecutorService结合使用:通过ExecutorService的submit()方法提交一个实现Callable接口的任务,然后ExecutorService的submit()方法会返回一个实现Future接口的对象,接着调用Future接口的get()方法就可以获取异步任务的结果。
东阳马生架构
2025/05/06
680
JUC并发—14.Future模式和异步编程分析一
Future/Callable实现了一个异步执行并带有返回结果的功能。Future表示获取一个异步执行的结果,Callable表示一个异步执行的任务,Callable会产生一个结果并给到Future。
东阳马生架构
2025/05/07
1240
聊聊Java中CompletableFuture的使用
CompletableFuture是java8引入的一个异步类,它最大的优势是可以在创建的对象中传入一个回调对象,在任务结束后(done或throw exception),自动调用回调对象的回调方法,而不用让主线程阻塞。
jinjunzhu
2020/08/20
8980
有了Future为什么还要CompletableFuture?
cheese
2024/02/06
2410
有了Future为什么还要CompletableFuture?
并发编程 - CompletableFuture
常见的线程创建方式有两种,一是直接继承Thread,另一种是实现Runnable接口。但这两种方式有个缺点,不支持获取线程执行结果。
小小工匠
2023/08/02
3390
并发编程 - CompletableFuture
JAVA 拾遗--Future 模式与 Promise 模式
写这篇文章的动机,是缘起于微信闲聊群的一场讨论,粗略整理下,主要涉及了以下几个具体的问题: 同步,异步,阻塞,非阻塞的关联及区别。 JAVA 中有 callback 调用吗? jdk 包中的 Future 怎么用? Future 模式和 Promise 模式是包含的关系,还是交集的关系,还是没有关系? 带着上面这些疑问,来看看我到底要拾遗些啥。 浅析同步,异步,阻塞,非阻塞 这几个概念一直困扰着我,说实话我现在依旧不能从一个很深的层次去和一个小白解释,这几个概念到底有什么区别。本节我不掺杂自己的描述,主要
kirito-moe
2018/04/27
7K0
Future模式
  【1】Future模式是多线程开发中常见的设计模式,它的核心思想是异步调用。对于Future模式来说,它无法立即返回你需要的数据,但是它会返回一个契约,将来你可以凭借这个契约去获取你需要的信息。
忧愁的chafry
2022/10/30
7110
Future模式
深入理解 Java 异步编程:Future 和 CompletableFuture 的全面比较
综上所述,CompletableFuture是Java中更强大和灵活的异步编程工具,但它也更复杂。Future是一种基本的异步编程接口,适用于简单的异步任务。根据具体需求和复杂性,你可以选择使用其中之一或根据场景组合它们。
一只牛博
2025/05/31
1020
Java8新的异步编程方式 CompletableFuture(一)
JDK 5引入了Future模式。Future接口是Java多线程Future模式的实现,在java.util.concurrent包中,可以来进行异步计算。
fengzhizi715
2018/08/24
2.2K0
一次性解决老大难问题:线程治理 Futrue、Callable接口、CompletableFuture
线程治理最重要的是线程池了,之前我讲过,但是,还有两大法宝就是future 和 callable
Joseph_青椒
2023/08/26
1K0
一次性解决老大难问题:线程治理 Futrue、Callable接口、CompletableFuture
异步编程 - 05 基于JDK中的Future实现异步编程(中)_CompletableFuture
Java8 - 使用工厂方法 supplyAsync创建 CompletableFuture
小小工匠
2023/09/09
3330
Java8 CompletableFuture 编程
 所谓异步调用其实就是实现一个无需等待被调用函数的返回值而让操作继续运行的方法。在 Java 语言中,简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结果。但调用者仍需要取线程的计算结果。
JMCui
2019/08/18
1.1K0
使用 Future 进行并发编程
在编程的时候,常常会遇到需要并行处理一些代码,最原始的做法就是创建不同的线程进行处理,但是线程之间的同步处理非常麻烦而且容易出错,如果要同时得到几个线程的结果并且通过这些结果进行进一步的计算,则需要共享变量或者进行线程间通信,无论如何都非常难以处理。另外,直接使用线程也使得代码灵活性不高,比如在双核机器上可能只希望使用两个线程执行代码,到了四核机器上就希望最多能有四个线程了。Future 能够提供一个高层的抽象,将计算任务的并发化和计算最终的执行方式分离,使得这类处理更为方便。Future 作为一个代理对象代表一个可能完成也可能未完成的值 1,通过对 future 进行操作,能够获取内部的计算是否已经完成,是否出现异常,计算结果是什么等信息。
zhiruili
2021/08/10
1.1K0
JUC并发—14.Future模式和异步编程分析二
CompletionStage表示任务执行的一个阶段,每个异步任务都会返回一个新的CompletionStage对象,可针对多个CompletionStage对象进行串行、并行、聚合等操作。简单来说,CompletionStage就是实现异步任务执行后的自动回调功能。
东阳马生架构
2025/05/07
720
异步编程利器 CompletableFuture 玩法详解
在上篇文章中,我们介绍了Future相关的用法,使用它可以获取异步任务执行的返回值。
Java极客技术
2024/01/17
3640
异步编程利器 CompletableFuture 玩法详解
CompletableFuture原理与实践-外卖商家端API的异步化
总第509篇 2022年 第026篇 CompletableFuture由Java 8提供,是实现异步化的工具类,上手难度较低,且功能强大,支持通过函数式编程的方式对各类操作进行组合编排。相比于ListenableFuture,CompletableFuture有效提升了代码的可读性,解决了“回调地狱”的问题。本文主要讲述CompletableFuture的原理与实践,同时结合了美团外卖商家端API的异步化实战,希望能对从事相关开发的同学有所帮助或启发。 0 背景 1 为何需要并行加载 2 并行加载的实现
美团技术团队
2022/05/12
1.6K0
CompletableFuture原理与实践-外卖商家端API的异步化
CompletableFuture异步回调
  Future模式是高并发设计与开发过程中常见的设计模式,它的核心思想是异步调用。对于Future模式来说,它不是立即返回我们所需要的数据,但是它会返回一个契约(或异步任务),将来我们可以凭借这个契约(或异步任务)获取需要的结果。
别团等shy哥发育
2023/10/17
5540
CompletableFuture异步回调
CompletableFuture在RocketMQ中的使用实战!
今天想跟大家来聊一聊JDK1.8提供的异步神器CompletableFuture,
程序员蜗牛
2024/02/18
2090
CompletableFuture在RocketMQ中的使用实战!
Java8使用CompletableFuture的部分方法
CompletableFuture的使用是为了异步编程,异步编程可以解决同步编程的性能瓶颈问题。也就是将同步操作变为了并行操作。 当我们有一大批数据需要处理的时候我们可以将这些数据分而治之,使用CompletableFuture通过线程池的多个线程进行异步执行。
袁新栋-jeff.yuan
2020/08/26
1.6K0
推荐阅读
相关推荐
并行设计模式--Future、Callback、Promise
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验