欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

Java 中的 CompletableFuture 和虚拟线程 21

最编程 2024-07-16 14:17:46
...

随着 Java 21 的发布,虚拟线程被引入作为可完成的 future 和线程的替代并发模型。可完成的 future 和虚拟线程都旨在简化 Java 中的异步编程,但采取了不同的方法。本文探讨了两者之间的主要区别。

什么是CompletableFutures?

CompletableFuture 是 Java 8 中添加的一个类,表示可以产生结果或异常完成的异步计算。它实现了 Future 接口,并提供了手动完成 future、等待完成、注册回调以及将可计算阶段链接在一起的方法。

CompletableFuture 的主要特点:

  • 异步操作——等待结果时不会阻塞主线程。
  • 回调——可以注册回调以在未来完成时执行。
  • 链式处理 - future 可以链接在一起以管道异步步骤。
  • 异常处理——异常是通过回调显式处理的。
  • 线程池——默认在 ForkJoinPool 公共线程池上运行计算。

CompletableFutures 通过将线程管理与应用程序逻辑解耦来实现异步编程。然而,它们仍然会遇到诸如回调地狱之类的问题,并且使用起来并不总是直观的。

用法示例:

// Run two async tasks
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
  // long running task 
  return "Result1";
});

CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
  // long running task
  return "Result2";  
});

// Join tasks and handle results
future1.thenCombine(future2, (res1, res2) -> {
  return res1 + " " + res2;
}).thenAccept(System.out::println);

CompletableFuture 易于使用,并且可以很好地扩展,适合中等数量的异步任务。但是,如果创建太多实例,可能会产生开销。

什么是虚拟线程?

Java 14 中引入了虚拟线程作为异步编程的替代方法。关键思想是,我们可以切换由 Java 运行时自动映射到真实线程的虚拟线程,而不是显式管理线程池。

虚拟线程的主要特点:

  • 轻量级——与操作系统线程相比,内存和资源开销较低。
  • 托管阻塞——阻塞操作不会阻塞操作系统线程,从而将它们释放以执行其他任务。
  • 结构化并发——虚拟线程从父线程继承上下文。
  • 异步——不需要基于回调的代码。可以使用同步代码风格。
  • 优化的扩展——可以有效地启动数千个虚拟线程。

个例子:

public class Main {

  public static void main(String[] args) {

    VirtualThread vt = VirtualMachine.getInstance().virtualThread(
      () -> {
        // long running task 
      }
    );

    vt.start();
    // can continue executing main thread logic

  }

}

虚拟线程旨在提供更简单的线程模型,可以更好地扩展并避免诸如回调地狱之类的问题。编程模型更像是同步代码,但执行是异步的。

主要差异

可完成的 future 和虚拟线程之间的一些主要区别:

  • 风格 - CompletableFuture 具有基于回调的风格,而虚拟线程允许异步逻辑的同步编码风格。
  • 阻塞——虚拟线程上的阻塞操作不会像可完成的未来那样消耗操作系统线程。
  • 开销——虚拟线程的资源开销比可完成的 future 使用的线程/线程池低。
  • 结构化并发——虚拟线程从父线程继承上下文,而可完成的 future 没有内置的父子关系概念。
  • 链接——CompletableFuture 可以更轻松地将多个未来阶段直接链接在一起。使用虚拟线程链接逻辑需要显式代码。
  • 错误处理——虚拟线程上未处理的异常会终止线程,而可完成的 future 需要通过回调进行处理。

总结:

  • CompletableFuture 是高级的、灵活的,但会产生开销。对于编写许多小任务很有用。
  • 虚拟线程是轻量级的并提供结构化并发。更适合较少的长时间运行任务。

两者都有其优点和用例,但虚拟线程代表了 Java 平台上异步编程的演变。两者之间的选择取决于应用程序要求和首选编程风格

推荐阅读