【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,并加入到 CompletableFuture 的 waiters 链表中。
  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:两种异步哲学

CompletableFuture 和 Reactive 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. 往期博客回顾

相关推荐
小羊没烦恼!3 天前
微服务化的基石——持续集成
java·大数据·word·powerpoint·.net
俊昭喜喜里3 天前
java中的继承和多态的区别
java
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
胡写代码3 天前
别再前后端各写一套表单校验了
java·后端
小鱼能吃糖3 天前
缺陷修复总览 · mall电商项目:5类缺陷,1个病根,4个业务域
java·电商
此时不提桶,更待何时3 天前
01-06-A-JVM排查实战详解
java·jvm
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
ba_pi4 天前
mysql 查询所有表名并授权
java
ProcessOn官方账号4 天前
java函数式编程--入门基础
java·编程·函数式编程