深入理解 Java 异步编程:Future 和 CompletableFuture 的全面比较

2023-09-21 09:07:20

深入理解 Java 异步编程:Future 和 CompletableFuture 的全面比较

理解Future和CompletableFuture的底层实现、用法以及它们的优劣势对深入了解这两个概念非常重要。我将从底层开始,详细解释它们,然后根据不同场景和需求讨论它们的优点和局限性。

Future

底层实现

  • Future是一个接口,通常由Executor框架提供实现。它的核心是一个get()方法,该方法用于阻塞当前线程,等待异步任务的完成,并返回任务的结果或抛出异常。
  • Future的简单实现可能只是一个包装器,它保存了异步任务的引用,并在get()方法中等待任务完成。

用法

  • Future适合单一异步任务的场景,其基本用法如下:
    1. 创建Future对象,通常使用ExecutorService来提交异步任务。
    2. 使用get()方法等待任务完成并获取结果,但此方法会阻塞当前线程,直到任务完成。
    3. 可以使用isDone()来检查任务是否已经完成。
    4. 如果任务失败,可以使用get()方法捕获异常。

下面是一个使用Future的示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureExample {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);
        
        // 提交异步任务
        Future<Integer> future = executor.submit(() -> {
            Thread.sleep(2000); // 模拟耗时操作
            return 42;
        });
        
        try {
            // 等待任务完成并获取结果
            Integer result = future.get(); // 阻塞等待结果
            System.out.println("Result: " + result);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}

这个示例演示了如何使用Future来执行异步任务,并在任务完成后获取结果。请注意,get()方法是阻塞的,所以它会等待任务完成后才会继续执行。

优点

  1. 简单易用:Future提供了一种基本的异步编程方式,容易理解和使用。
  2. 阻塞等待:对于需要等待异步任务完成并获取结果的场景,Future的阻塞式get()方法非常方便。

局限性

  1. 阻塞:Future的get()方法是阻塞的,如果任务执行时间较长,会导致当前线程阻塞。
  2. 无法组合:难以处理多个异步任务的组合和串联,使得复杂流程难以实现。
  3. 异常处理有限:异常处理较为受限,必须通过捕获异常来处理错误情况。

CompletableFuture

底层实现

  • CompletableFuture是Java 8引入的一个强大的异步编程工具,基于Future进行扩展。
  • 它的底层实现依赖于Java的ForkJoinPool和一些并发工具类。
  • CompletableFuture内部使用回调链来处理异步任务的完成和组合。

用法

  • CompletableFuture非常灵活,可以实现复杂的异步编程流程,包括多个任务的组合、串联和异常处理:
    1. 使用CompletableFuture.supplyAsync()CompletableFuture.runAsync()提交异步任务。
    2. 使用thenApply(), thenCompose(), thenCombine()等方法定义操作链。
    3. 使用exceptionally()handle()来处理异常情况。
    4. 使用allOf()anyOf()组合多个CompletableFuture。

示例:

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        // 异步任务,返回结果为42
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 42);
        
        // 对结果进行处理,然后打印
        future.thenApply(result -> result * 2)
              .thenAccept(finalResult -> System.out.println("Final Result: " + finalResult));
    }
}

这个示例中,我们使用CompletableFuture.supplyAsync()提交了一个异步任务,然后使用thenApply()方法对结果进行处理,并最终使用thenAccept()方法打印结果。这个流水线是非阻塞的,所以可以更灵活地组织异步操作。

优点

  1. 组合和串联:CompletableFuture提供了丰富的操作方法,允许你轻松组合和串联多个异步任务,构建复杂的流程。
  2. 非阻塞:操作链中的任务是非阻塞的,可以提高并发性能。
  3. 异常处理:支持异常处理,可以更好地处理错误情况。
  4. 可手动完成:你可以手动完成CompletableFuture,这在某些场景下很有用。

局限性

  1. 复杂性:对于简单的异步任务,使用CompletableFuture可能会显得过于复杂。
  2. 学习曲线:相对于Future,使用CompletableFuture需要更多的学习和理解异步编程概念。

选择适合的场景和需求:

  • Future适合于简单的异步任务,当你只需要等待任务完成并获取结果时。
  • CompletableFuture适用于需要更复杂异步操作流程、组合多个任务、处理异常情况的场景。
  • 如果你的应用程序需要高度并发和复杂的异步操作,CompletableFuture通常更适合。
  • 选择取决于任务的复杂性、性能要求以及是否需要灵活的异步操作控制。

综上所述,CompletableFuture是Java中更强大和灵活的异步编程工具,但它也更复杂。Future是一种基本的异步编程接口,适用于简单的异步任务。根据具体需求和复杂性,你可以选择使用其中之一或根据场景组合它们。

更多推荐

终端数据防泄漏

需求背景随着各行各业业务数据信息化发展,各类产品研发及设计等行业,都有关乎自身发展的核心数据,包括业务数据、代码数据、机密文档、用户数据等敏感信息,这些信息数据有以下共性:属于核心机密资料,万一泄密会对企业造成恶劣影响,包括市场占有率下降、丧失核心竞争力、损失客户信心等各种显性与隐性影响;核心数据类型多,还有业务系统数

Java基于SpringBoot的高校招生管理系统,附源码,教程

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W+,Csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌文章目录简介系统设计思路1数据库设计2系统整体设计2.1系统设计思想2.2系统流程图系统详细设计1系统功能模块2.管理员功能模块3学生功能模块六源码咨询

钉钉旧版服务端SDK支持异步方法的升级改造

最近项目中需要对接钉钉,有些钉钉API的访问需要使用旧版服务端SDK才能搞定,但是这个SDK使用的还是.NETFramework2.0框架,不能跨平台部署,也不支持async\await的异步操作方法,Nuget上也有其它用户改造的.NETCore版本,但是都不支持异步方法,于是就想自己改造一下,经过若干小时的改造,最

Stable Diffusion 系统教程 | 强大的ControlNet 控制网

2023年的2月13日,一款名叫ControlNet的插件横空出世,AI绘画变得更加可控ControlNet直译过来很简单,就叫做控制网,开发者是一名华裔,毕业于苏州大学,目前在斯坦福做读博士一年级,大佬大佬!在controlNet之前,基于扩散模型的绘画是极为难控制的,平时自嗨画画其实没有一点问题,随机就随机一点,但

Java 中的四种引用方式

文章目录Java中的四种引用方式1、强引用(StrongReference)(1)弱化方式1(2)弱化方式22、软引用(SoftReference)3、弱引用(WeakReference)4、虚引用(PhantomReference)Java中的四种引用方式1、强引用(StrongReference)强引用是最普遍的引

【Python】Python 模式匹配与正则表达式

Python模式匹配与正则表达式1.模式匹配与正则表达式你可能熟悉文本查找,即按下Ctrl-F,输入你要查找的词。“正则表达式”更进一步,它们让你指定要查找的“模式”。你也许不知道一家公司的准确电话号码,但如果你住在美国或加拿大,你就知道它有3位数字,然后是一个短横线,然后是4位数字(有时候以3位区号开始)。因此作为一

Android SurfaceFlinger导读(02)MessageQueue

该系列文章总纲链接:AndroidGUI系统之SurfaceFlinger系列文章目录说明:关于导读:导读部分主要是方便初学者理解SurfaceFlinger代码中的机制,为后面分析代码打下一个更好的基础,这样就可以把更多的精力放在surfaceFlinger的业务逻辑分析上。关于代码分支:以下代码分析均在androi

单元测试框架-pytest

单元测试框架-pytest官网常用插件pytest-html:生成html报告pytest-xdist:实现并发测试pytest-ordering:实现测试用例顺序设置pytest-rerunfailures:测试用例失败重试allure-pytest:生成测试报告引入依赖在项目根目录下创建:requirements.

RK3568开发笔记(七):在宿主机ubuntu上搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/132733901红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…瑞芯微开

Docker和debezium是什么关系,如何部署?

目录一、什么是Docker二、什么是debezium一、什么是DockerDocker是一种开源的容器化平台,用于构建、部署和运行应用程序。它通过将应用程序及其依赖项打包到一个称为容器的独立单元中,使应用程序能够在不同的环境中以一致的方式运行。以下是Docker的一些核心概念和特性:容器:Docker使用容器来封装应用

RK3568开发笔记(十):开发板buildroot固件移植开发的应用Demo,启动全屏显示

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/133021990红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…瑞芯微开

热文推荐