【Java线程安全实战】⑨ CompletableFuture的高级用法:从基础到高阶,结合虚拟线程

📖目录

  • 引言:为什么我们需要CompletableFuture?
  • [1. 前传:Future 与 CompletableFuture 的爱恨情仇](#1. 前传:Future 与 CompletableFuture 的爱恨情仇)
    • [1.1 Future:异步编程的"半成品"](#1.1 Future:异步编程的“半成品”)
    • [1.2 CompletableFuture:Future 的"完全体"](#1.2 CompletableFuture:Future 的“完全体”)
  • [2. 大白话解释:CompletableFuture如何工作?](#2. 大白话解释:CompletableFuture如何工作?)
  • [3. 源码深潜:CompletableFuture 的内部引擎](#3. 源码深潜:CompletableFuture 的内部引擎)
    • [3.1 核心数据结构:Completion 链表](#3.1 核心数据结构:Completion 链表)
    • [3.2 join() 的奥秘:UNSAFE 与 LockSupport](#3.2 join() 的奥秘:UNSAFE 与 LockSupport)
  • [4. 多个CompletableFuture的组合艺术:allOf vs anyOf](#4. 多个CompletableFuture的组合艺术:allOf vs anyOf)
    • [4.1 allOf:团队协作,一个都不能少](#4.1 allOf:团队协作,一个都不能少)
    • [4.2 anyOf:竞速模式,先到先得](#4.2 anyOf:竞速模式,先到先得)
  • [5. 异常处理的高级技巧:优雅地面对"翻车"](#5. 异常处理的高级技巧:优雅地面对“翻车”)
    • [5.1 exceptionally:专属的"急救包"](#5.1 exceptionally:专属的“急救包”)
    • [5.2 handle:无论成败,都要有个交代](#5.2 handle:无论成败,都要有个交代)
  • [6. 与虚拟线程(Virtual Threads)的完美结合](#6. 与虚拟线程(Virtual Threads)的完美结合)
    • [6.1 虚拟线程:轻量级的"协程"](#6.1 虚拟线程:轻量级的“协程”)
    • [6.2 CompletableFuture + 虚拟线程 = 高并发新范式](#6.2 CompletableFuture + 虚拟线程 = 高并发新范式)
  • [7. CompletableFuture vs Reactive Streams:两种异步哲学](#7. CompletableFuture vs Reactive Streams:两种异步哲学)
  • [8. 实战示例:微服务间的异步调用](#8. 实战示例:微服务间的异步调用)
    • [8.1 示例1:使用allOf聚合多个微服务响应](#8.1 示例1:使用allOf聚合多个微服务响应)
    • [8.2 示例2:使用anyOf实现服务降级](#8.2 示例2:使用anyOf实现服务降级)
    • [8.3 示例3:结合虚拟线程处理海量请求](#8.3 示例3:结合虚拟线程处理海量请求)
    • [8.4 示例4:完整的异常处理链](#8.4 示例4:完整的异常处理链)
  • [9. 结语:CompletableFuture不是银弹,但它是异步编程的利器](#9. 结语:CompletableFuture不是银弹,但它是异步编程的利器)
  • [10. 经典书籍推荐](#10. 经典书籍推荐)
  • [11. 下一篇预告](#11. 下一篇预告)
  • [12. 往期博客回顾](#12. 往期博客回顾)

引言:为什么我们需要CompletableFuture?

想象一下,你正在筹备一场大型婚礼。你需要同时协调多个供应商:摄影师、化妆师、酒店、婚庆公司。如果采用传统的同步方式,你会这样操作:

  1. 先打电话给摄影师,等他确认档期。
  2. 然后打电话给化妆师,等她确认档期。
  3. 接着联系酒店...
    整个过程是串行的,效率极低。万一某个环节出问题(比如酒店临时涨价),你可能会手忙脚乱。

在软件世界里,我们经常面临类似场景:需要同时调用多个外部服务(如用户服务、订单服务、库存服务),并等待它们的结果。CompletableFuture 就是为了解决这种复杂异步协作而生的。它让你可以像指挥家一样,优雅地编排多个异步任务,无论是等待所有任务完成(allOf),还是只关心最快的那个结果(anyOf),甚至是处理各种意外情况(异常处理)。

更重要的是,在 Java 21 引入了虚拟线程(Virtual Threads)之后,CompletableFuture 的威力被进一步放大,为我们构建超高并发、低延迟的应用提供了全新的可能性。


1. 前传:Future 与 CompletableFuture 的爱恨情仇

在深入 CompletableFuture 之前,我们必须理解它的前辈------Future。它们之间的关系,就像是从"能跑的马车"进化到了"带自动驾驶的智能汽车"。

1.1 Future:异步编程的"半成品"

java.util.concurrent.Future 是 Java 5 引入的接口,代表一个异步计算的结果。它的核心思想是:"我现在去办事,给你一张凭证(Future),你稍后再凭这张凭证来取结果。"

java 复制代码
// Future 的典型用法
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(() -> {
    // 模拟耗时任务
    Thread.sleep(1000);
    return "Hello, Future!";
});

// 主线程可以去做别的事...
// ...

// 在需要结果时,阻塞等待
String result = future.get(); // 这里会阻塞!

Future 的三大痛点

  1. 被动等待 :你无法主动为 Future 注册回调。唯一获取结果的方式就是调用 get(),这会导致当前线程阻塞,失去了异步的意义。
  2. 无法组合 :如果有两个 Future,你想等它们都完成后再做点事?抱歉,Future 本身不提供任何组合方法,你只能手动轮询或阻塞。
  3. 异常处理笨拙get() 方法会抛出 ExecutionException,你需要手动解包才能拿到真正的业务异常。

简而言之,Future 只解决了"异步执行"的问题,但没有解决"异步协作"和"非阻塞处理结果"的问题。


1.2 CompletableFuture:Future 的"完全体"

CompletableFuture 在 Java 8 中诞生,它实现了 Future 接口 ,因此它首先是一个 Future。但它更是一个强大的构建块(Building Block) ,因为它引入了函数式编程声明式组合的能力。

特性 Future CompletableFuture
是否实现 Future
主动回调 ❌ 不支持 ✅ 支持 (thenApply, thenAccept 等)
任务组合 ❌ 不支持 ✅ 支持 (allOf, anyOf, thenCombine 筇)
异常处理 ❌ 笨拙 (get() 抛异常) ✅ 优雅 (exceptionally, handle)
手动完成 ❌ 不可能 ✅ 可以 (complete(), completeExceptionally())

CompletableFuture 不仅继承了 Future 的衣钵,更通过一系列流畅的 API,让我们能够以非阻塞、声明式的方式,将多个异步任务编织成一张复杂的协作网络。这才是现代异步编程应有的样子。


2. 大白话解释:CompletableFuture如何工作?

可以把 CompletableFuture 想象成一个"智能快递单"。

  • 下单(创建Future) :当你发起一个异步任务(比如 supplyAsync),就像下了一个快递单。此时你手上只有一个单号(CompletableFuture 对象),包裹(结果)还在路上。
  • 追踪与处理(回调) :你可以在这个单号上注册一系列操作,比如"包裹到了通知我"(thenAccept)、"包裹到了帮我拆开并把里面的东西转寄给另一个人"(thenApply)。这些操作会形成一个链条。
  • 最终交付(获取结果) :当所有前置任务都完成后,你最终可以通过 join()get() 拿到包裹(结果),或者通过回调自动处理它。

这种"声明式"的编程方式,让你的代码逻辑清晰,避免了传统回调地狱(Callback Hell)的混乱。


3. 源码深潜:CompletableFuture 的内部引擎

CompletableFuture 的魔力并非凭空而来,其内部精巧的设计是性能和功能的基石。我们来揭开它的面纱。

3.1 核心数据结构:Completion 链表

CompletableFuture 的核心在于一个名为 Completion 的内部抽象类。每一个你在 CompletableFuture 上注册的回调(如 thenApply, thenAccept),都会被封装成一个 Completion 的子类实例(例如 UniApply, UniAccept)。

这些 Completion 实例会以 (Stack)的形式(通过 next 指针链接)挂载在对应的 CompletableFuture 对象上。

流程图:CompletableFuture 回调链
stack
next
next
当 cf 完成时
cf.result = value
for c in stack: c.tryFire
C1.tryFire
C2.tryFire
C3.tryFire
CompletableFuture cf
Completion C3
Completion C2
Completion C1

执行流程

  1. CompletableFuture 的任务完成(通过 complete(value)obtrudeValue(value))时,它会将结果存入内部的 result 字段。
  2. 紧接着,它会遍历自己身上挂载的 Completion 栈。
  3. 对每个 Completion 调用 tryFire(mode) 方法。这个方法会检查其依赖的 CompletableFuture 是否已完成,如果已完成,就执行具体的回调逻辑(如 apply 函数),并将结果传递给下一个 CompletableFuture
  4. 这个过程会像多米诺骨牌一样,沿着回调链一路触发下去,直到所有依赖的任务都完成。

这种设计使得任务的触发是惰性 (Lazy)且高效 的,只有在源头 Future 完成后,后续的计算才会被激活。


3.2 join() 的奥秘:UNSAFE 与 LockSupport

当我们调用 cf.join() 时,如果 cf 还未完成,当前线程会阻塞。那么,JVM 是如何知道何时唤醒这个线程的呢?

答案就在 join() 方法的底层实现中,它最终会调用到 awaitDone(boolean timed, long nanos) 方法。其核心逻辑如下:

  1. 自旋检查 :首先在一个循环中快速检查 result 字段是否已经设置(使用 UNSAFE.getObjectVolatile 保证可见性)。这是为了应对任务恰好在调用 join() 后瞬间完成的情况,避免不必要的线程挂起开销。
  2. 线程挂起 :如果自旋几次后任务仍未完成,当前线程会被封装成一个 WaitNode,并加入到 CompletableFuturewaiters 链表中。
  3. 调用 LockSupport.park() :然后,线程会调用 LockSupport.park() 进入WAITING状态,释放CPU。
  4. 唤醒机制 :当 CompletableFuture 最终完成时,在遍历 Completion 链的同时,也会遍历 waiters 链表,并对其中的每个 WaitNode 调用 LockSupport.unpark(thread)
  5. 线程恢复 :被 unpark 的线程会从 park() 处恢复执行,再次检查 result,此时必然已有值,于是返回结果。

这个过程巧妙地结合了自旋 (减少上下文切换)和阻塞(避免CPU空转),是Java并发库中非常经典的等待/通知模式。


4. 多个CompletableFuture的组合艺术:allOf vs anyOf

CompletableFuture 最强大的地方在于它能轻松组合多个异步任务。

4.1 allOf:团队协作,一个都不能少

CompletableFuture.allOf(...) 就像一个项目负责人,必须等到所有团队成员(子任务)都提交了报告,他才能汇总并向老板汇报。

特性 allOf 生活比喻
触发条件 所有传入的 CompletableFuture 都完成 婚礼所有供应商都确认到位
返回值 CompletableFuture<Void>,本身不携带结果,但可以用来触发后续动作 一个"万事俱备"的信号
异常处理 任何一个子任务失败,allOf 也会立即失败 任何一个供应商掉链子,整个婚礼计划就泡汤

4.2 anyOf:竞速模式,先到先得

CompletableFuture.anyOf(...) 则像是一个竞标系统,只要有任何一个投标方(子任务)给出了报价,就可以立刻成交。

特性 anyOf 生活比喻
触发条件 任意一个传入的 CompletableFuture 完成 多个快递公司抢单,谁先送到算谁的
返回值 CompletableFuture<Object>,其结果是第一个完成的任务的结果 第一个送达的包裹
异常处理 如果第一个完成的任务是成功的,anyOf 就成功;如果第一个完成的是异常,则 anyOf 也失败 第一个快递员如果顺利送达,交易成功;如果他半路出了事故(异常),交易也算失败

5. 异常处理的高级技巧:优雅地面对"翻车"

现实世界充满了不确定性,网络超时、服务宕机都是家常便饭。CompletableFuture 提供了强大的异常处理机制。

5.1 exceptionally:专属的"急救包"

exceptionally 允许你为一个特定的 CompletableFuture 注册一个"急救方案"。如果这个任务失败了,就执行这个方案,并用它的返回值作为最终结果,从而让整个流程继续下去。

java 复制代码
// 示例:如果获取用户信息失败,返回一个默认的匿名用户
CompletableFuture<User> future = getUserAsync(userId)
    .exceptionally(ex -> {
        System.err.println("获取用户失败: " + ex.getMessage());
        return new User("anonymous");
    });

5.2 handle:无论成败,都要有个交代

handle 是一个更通用的方法。它接收两个参数:正常结果(可能为null)和异常(可能为null)。你可以在一个方法里统一处理成功和失败两种情况。

java 复制代码
// 示例:记录日志,无论成功与否
CompletableFuture<String> result = fetchData()
    .handle((data, ex) -> {
        if (ex != null) {
            log.error("数据获取失败", ex);
            return "DEFAULT_DATA";
        } else {
            log.info("数据获取成功");
            return data;
        }
    });

6. 与虚拟线程(Virtual Threads)的完美结合

Java 21 引入的虚拟线程(Project Loom)是革命性的。传统平台线程(Platform Threads)很重,创建成千上万个成本高昂。而虚拟线程非常轻量,由 JVM 管理,可以轻松创建数百万个。

6.1 虚拟线程:轻量级的"协程"

可以把平台线程想象成"正式员工",每个都需要独立的办公桌(操作系统资源)。而虚拟线程则是"实习生",他们共享办公桌,由一个"经理"(载体平台线程)来调度。当一个实习生在等待(比如I/O操作)时,经理可以立刻切换到另一个实习生,极大地提高了资源利用率。


6.2 CompletableFuture + 虚拟线程 = 高并发新范式

过去,我们使用 CompletableFuture.supplyAsync(...) 时,通常会传入一个线程池(如 ForkJoinPool.commonPool())。在线程池大小有限的情况下,大量阻塞的 I/O 操作会很快耗尽线程,导致系统无法处理新请求。

现在,我们可以直接在虚拟线程中执行阻塞操作!因为虚拟线程的成本极低,即使有成千上万个虚拟线程在等待 I/O,JVM 也能高效地管理它们。

这意味着,对于 I/O 密集型任务,我们甚至可以简化代码,直接使用 CompletableFuture 的链式调用,而无需过度担心线程池的配置,因为底层的虚拟线程已经为我们解决了并发瓶颈。


7. CompletableFuture vs Reactive Streams:两种异步哲学

CompletableFutureReactive Streams(如 Project Reactor 的 Mono/Flux)都是处理异步流的强大工具,但它们的设计哲学不同。

特性 CompletableFuture Reactive Streams
核心思想 Future/Promise 模型:代表一个未来会完成的单一值。 发布-订阅模型:代表一个可能包含0到N个元素的数据流。
背压(Backpressure) 不支持。生产者和消费者之间没有速率协商机制。 核心特性。消费者可以控制生产者的发送速率,防止被淹没。
适用场景 RPC调用、数据库查询等返回单一结果的场景。 事件流处理、实时数据管道等处理连续数据流的场景。
学习曲线 相对平缓,概念直观。 较陡峭,需要理解背压、操作符等概念。
与虚拟线程 天然契合。虚拟线程解决了其I/O阻塞的痛点。 已有自己的非阻塞I/O模型,虚拟线程对其影响较小。

简单来说,如果你的任务是"问一个问题,等一个答案",CompletableFuture 是绝佳选择。如果你的任务是"监听一条消息河,对每条消息做处理",那么 Reactive Streams 更合适。


8. 实战示例:微服务间的异步调用

下面我们将通过四个完整的示例,展示 CompletableFuture 在微服务场景下的强大能力。

8.1 示例1:使用allOf聚合多个微服务响应

场景:在一个电商应用中,渲染商品详情页需要同时获取商品信息、用户评论和推荐商品。这三个服务调用可以并行进行。

java 复制代码
// 【插入 Example1_AllOf.java】
import java.util.concurrent.CompletableFuture;

public class Example1_AllOf {
    // 模拟微服务调用
    private static CompletableFuture<String> fetchProductInfo() {
        return CompletableFuture.supplyAsync(() -> {
            try { Thread.sleep(1000); } catch (InterruptedException e) { }
            return "Product Info: iPhone 15";
        });
    }

    private static CompletableFuture<String> fetchReviews() {
        return CompletableFuture.supplyAsync(() -> {
            try { Thread.sleep(1200); } catch (InterruptedException e) { }
            return "Reviews: [Great phone!]";
        });
    }

    private static CompletableFuture<String> fetchRecommendations() {
        return CompletableFuture.supplyAsync(() -> {
            try { Thread.sleep(800); } catch (InterruptedException e) { }
            return "Recommendations: [AirPods, Case]";
        });
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        CompletableFuture<String> productFuture = fetchProductInfo();
        CompletableFuture<String> reviewsFuture = fetchReviews();
        CompletableFuture<String> recommendationsFuture = fetchRecommendations();

        // 等待所有服务调用完成
        CompletableFuture<Void> allDone = CompletableFuture.allOf(
            productFuture, reviewsFuture, recommendationsFuture
        );

        // 当所有任务完成后,组装最终页面
        allDone.thenRun(() -> {
            String page = String.format(
                "=== Product Detail Page ===\n%s\n%s\n%s",
                productFuture.join(),
                reviewsFuture.join(),
                recommendationsFuture.join()
            );
            System.out.println(page);
            System.out.println("Total time: " + (System.currentTimeMillis() - start) + "ms");
        }).join(); // 主线程等待
    }
}

执行结果预留位

复制代码
=== Product Detail Page ===
Product Info: iPhone 15
Reviews: [Great phone!]
Recommendations: [AirPods, Case]
Total time: 1274ms

8.2 示例2:使用anyOf实现服务降级

场景:为了提高系统的可用性,我们可以为关键服务部署主备实例。当主服务响应慢或失败时,可以快速切换到备用服务。

java 复制代码
// 【插入 Example2_AnyOf.java】
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class Example2_AnyOf {
    // 模拟一个可能很慢或失败的主服务
    private static CompletableFuture<String> callPrimaryService() {
        return CompletableFuture.supplyAsync(() -> {
            try {
                // 模拟网络延迟或故障:50%概率超时(3秒),50%概率抛异常
                if (Math.random() > 0.5) {
                    Thread.sleep(3000); // 主服务超时场景
                } else {
                    throw new RuntimeException("Primary service down! 主服务故障");
                }
            } catch (InterruptedException e) {
                // 修复:不再空吞异常,打印日志+包装成运行时异常抛出
                System.err.println("主服务请求被中断:" + e.getMessage());
                throw new RuntimeException("Primary service interrupted!", e);
            }
            return "Primary Result 【主服务正常结果】";
        })
        // 主服务抛异常时,返回一个异常占位值,而不是让Future进入失败状态
        .exceptionally(ex -> {
            System.err.println("主服务调用失败:" + ex.getMessage());
            return null; // 异常时返回null,标记主服务不可用
        });
    }

    // 模拟一个稳定但数据可能稍旧的备用服务
    private static CompletableFuture<String> callBackupService() {
        return CompletableFuture.supplyAsync(() -> {
            try { Thread.sleep(500); } catch (InterruptedException e) {
                System.err.println("备用服务请求被中断:" + e.getMessage());
            }
            return "Backup Result (slightly stale) 【备用服务兜底结果】";
        });
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        CompletableFuture<Object> fastResult = CompletableFuture.anyOf(
                callPrimaryService(),
                callBackupService()
        );

        try {
            String result = (String) fastResult.join();
            // 过滤主服务异常返回的null值
            if (result == null) {
                result = callBackupService().join(); // 兜底:主动调用备用服务
            }
            System.out.println("\n✅ Final result: " + result);
        } catch (Exception e) {
            // 极端情况:所有服务都失败,最终兜底提示
            System.out.println("\n⚠️ All services failed! Use default result");
        } finally {
            // 必输耗时,无论成功失败都统计
            System.out.println("⏱️ Response time: " + (System.currentTimeMillis() - start) + "ms");
        }
    }
}

执行结果预留位

复制代码
✅ Final result: Backup Result (slightly stale) 【备用服务兜底结果】
⏱️ Response time: 548ms

8.3 示例3:结合虚拟线程处理海量请求

场景:模拟一个高并发网关,需要同时处理成千上万个对外部服务的调用。我们将利用虚拟线程来实现。

java 复制代码
// 【插入 Example3_VirtualThreads.java,需要在JDK21或以上执行】
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;

public class Example3_VirtualThreads {
    // 创建虚拟线程
    private static final ExecutorService VIRTUAL_THREAD_POOL = Executors.newVirtualThreadPerTaskExecutor();

    // 模拟I/O密集型的外部服务调用(业务逻辑完全不变)
    private static CompletableFuture<String> callExternalService(int id) {
        return CompletableFuture.supplyAsync(() -> {
            // 模拟网络I/O等待 100ms
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // 正确处理中断异常:恢复中断标记 + 日志,不吞异常
                System.err.println("Virtual Thread-" + Thread.currentThread().threadId() + " 被中断, requestId=" + id);
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
            return "Response from service " + id;
        }, VIRTUAL_THREAD_POOL);
    }

    public static void main(String[] args) {
        int totalRequests = 10_000; // 1万并发IO请求
        long start = System.currentTimeMillis();

        // 创建1万个异步虚拟线程任务
        CompletableFuture<?>[] futures = IntStream.range(0, totalRequests)
                .mapToObj(Example3_VirtualThreads::callExternalService)
                .toArray(CompletableFuture[]::new);

        // 等待所有IO请求完成
        CompletableFuture.allOf(futures).join();

        long end = System.currentTimeMillis();
        // 输出耗时统计
        System.out.println("✅ Success! Processed " + totalRequests + " IO requests in " + (end - start) + "ms");

        // ✅ 这里可以安全调用shutdown()!!!
        VIRTUAL_THREAD_POOL.shutdown();
    }
}

执行结果预留位

复制代码
✅ Success! Processed 10000 IO requests in 157ms

8.4 示例4:完整的异常处理链

场景:在一个支付流程中,调用银行接口可能会失败。我们需要优雅地处理异常,并提供清晰的错误信息。

java 复制代码
// 【插入 Example4_ExceptionHandling.java】
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

public class Example4_ExceptionHandling {
    // 模拟一个不稳定的银行支付接口
    private static CompletableFuture<Boolean> processPayment(double amount) {
        return CompletableFuture.supplyAsync(() -> {
            if (amount > 1000) {
                throw new IllegalArgumentException("Amount too high!");
            }
            // 模拟支付成功
            return true;
        });
    }

    public static void main(String[] args) {
        CompletableFuture<String> paymentResult = processPayment(1500.0)
            .handle((success, ex) -> {
                if (ex != null) {
                    // 解包CompletionException以获取原始异常
                    Throwable cause = ex instanceof CompletionException ? ex.getCause() : ex;
                    return "Payment failed: " + cause.getMessage();
                } else {
                    return "Payment successful!";
                }
            });

        System.out.println(paymentResult.join());
    }
}

执行结果预留位

复制代码
Payment failed: Amount too high!

9. 结语:CompletableFuture不是银弹,但它是异步编程的利器

CompletableFuture 极大地简化了 Java 中的异步编程和并发任务编排。它让我们能够以声明式的方式构建复杂的异步逻辑,代码可读性和可维护性都得到了显著提升。

Future 的被动等待,到 CompletableFuture 的主动编排,再到与虚拟线程的珠联璧合,Java 的异步编程能力已经达到了一个新的高度。我们现在可以用接近同步代码的简洁性,写出性能媲美传统异步非阻塞模型的高并发程序。

正确使用 CompletableFuture 的时机

  • 需要组合多个异步任务(allOf, anyOf)。
  • 需要清晰的链式调用和回调处理。
  • 构建基于 RPC 或 REST API 调用的微服务应用。

不要过度使用的场景

  • CPU 密集型计算任务(应使用 ForkJoinPool)。
  • 需要处理背压的无限数据流(应考虑 Reactive Streams)。

掌握 CompletableFuture,是你迈向高并发、高性能 Java 开发的必经之路。


10. 经典书籍推荐

  • 《Java并发编程实战》(Java Concurrency in Practice)

    • 作者:Brian Goetz 等
    • 价值 :尽管出版较早,但这本书依然是 Java 并发领域的圣经。它奠定了现代 Java 并发编程的理论基础,书中关于 Future 的讨论是理解 CompletableFuture 的重要基石。
  • 《Java Performance Companion》

    • 作者:Charlie Hunt, Monica Beckwith, et al.
    • 价值 :这本书深入探讨了 Java 性能调优的各个方面,包括最新的垃圾回收器和 Project Loom(虚拟线程)。对于想深入理解 CompletableFuture 与虚拟线程结合后性能表现的开发者来说,是不可多得的参考资料。

11. 下一篇预告

在掌握了异步协作 (CountDownLatch, CyclicBarrier, Phaser) 和异步任务编排 (CompletableFuture) 之后,我们将在下一篇中探讨如何控制并发访问的资源数量 。敬请期待:【Java线程安全实战】⑩ 信号量的艺术:Semaphore 如何成为系统的"流量阀门"?


12. 往期博客回顾

相关推荐
冰冰菜的扣jio7 小时前
Redis缓存中三大问题——穿透、击穿、雪崩
java·redis·缓存
小璐猪头7 小时前
专为 Spring Boot 设计的 Elasticsearch 日志收集 Starter
java
ps酷教程8 小时前
HttpPostRequestDecoder源码浅析
java·http·netty
闲人编程8 小时前
消息通知系统实现:构建高可用、可扩展的企业级通知服务
java·服务器·网络·python·消息队列·异步处理·分发器
栈与堆8 小时前
LeetCode-1-两数之和
java·数据结构·后端·python·算法·leetcode·rust
OC溥哥9998 小时前
Paper MinecraftV3.0重大更新(下界更新)我的世界C++2D版本隆重推出,拷贝即玩!
java·c++·算法
星火开发设计8 小时前
C++ map 全面解析与实战指南
java·数据结构·c++·学习·算法·map·知识
*才华有限公司*8 小时前
RTSP视频流播放系统
java·git·websocket·网络协议·信息与通信
gelald9 小时前
ReentrantLock 学习笔记
java·后端