【并发编程JUC】Future和CompletableFuture机制

news/2024/5/20 9:11:28 标签: juc

场景题

面试的时候当面试官提出一个场景题,比如有一个翻译接口,同时调用百度、网易、谷歌的三个翻译接口,使用返回的第一个的翻译。这个时候一般的想法可能是,先串行执行。然后异步获取。但是其实都知道这样性能非常慢。

Future

如果直接使用Future的方式,我们知道Future的get接口是阻塞的,也就是在执行调用三方接口的返回结果的时候,需要阻塞等待结果。
在这里插入图片描述
其实整体的耗时就是取决于最短的三方接口响应,如果百度、网易、google分别是200、300、400毫秒,那么程序需要阻塞200毫秒。

    FutureTask<Integer> futureTask = new FutureTask<Integer>(() -> {
            Thread.sleep(10000);
            System.out.println("调用三方翻译接口");
            return 1024;
        });

        new Thread(futureTask).start();

        Integer integer = futureTask.get(); //会阻塞
        Integer integer = futureTask.get(1, TimeUnit.SECONDS);

        while (true) {
            if (futureTask.isDone()) {
                System.out.println("完成任务");
                break;
            } else {
                System.out.println("执行中,稍等.");
            }
        }
        Integer x = futureTask.get();
        System.out.println(x);

所以在实际的生产环境中,并不会使用get()。而是使用get超时机制,或者使用自定义的isDone() 轮询处理的方式。避免因为一个接口导致整体链路的阻塞。
如果想要异步获取结果,通常都会以轮询的方式去获取结果尽量不要阻塞

在这里插入图片描述
因为Future的继承图是来自Runable,所以启动线程的方式也是通过new Thread的方式开启。

CompletableFuture

为了解决上述Future的阻塞问题点,以及可以实现真正意义上的异步并发编程,所以引入了CompleablteFuture。
在这里插入图片描述

创建方式

## 无 返回值
 public static CompletableFuture<Void> runAsync(Runnable runnable,
                                                   Executor executor) {
        return asyncRunStage(screenExecutor(executor), runnable);
    }

 public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(asyncPool, runnable);
    }

## 有返回值
 public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }

其中executor可以进行自定义的线程池。没有指定Executor的方法,直接使用默认的ForkJoinPool.commonPool() 作为它的线程池执行异步代码。

CompletionStage

CompletionStage描述的是每个子任务,主要包含四个接口,thenApply、thenAccept、thenRun、thenCompose。

描述串行关系

CompletionStage<R> thenApply(fn);
CompletionStage<R> thenApplyAsync(fn);
CompletionStage<Void> thenAccept(consumer);
CompletionStage<Void> thenAcceptAsync(consumer);
CompletionStage<Void> thenRun(action);
CompletionStage<Void> thenRunAsync(action);
CompletionStage<R> thenCompose(fn);
CompletionStage<R> thenComposeAsync(fn);

案例

CompletableFuture<java.lang.String> completableFuture = CompletableFuture.supplyAsync(() -> {
            return "helloword";
        }).thenApply(s -> s + "qq");

需要一个执行完毕,在执行另一个。

描述AND关系

CompletionStage<R> thenCombine(other, fn);
CompletionStage<R> thenCombineAsync(other, fn);
CompletionStage<Void> thenAcceptBoth(other, consumer);
CompletionStage<Void> thenAcceptBothAsync(other, consumer);
CompletionStage<Void> runAfterBoth(other, action);
CompletionStage<Void> runAfterBothAsync(other, action);

描述 OR 汇聚关系

CompletionStage applyToEither(other, fn);
CompletionStage applyToEitherAsync(other, fn);
CompletionStage acceptEither(other, consumer);
CompletionStage acceptEitherAsync(other, consumer);
CompletionStage runAfterEither(other, action);
CompletionStage runAfterEitherAsync(other, action);

异常处理

CompletionStage exceptionally(fn);
CompletionStage<R> whenComplete(consumer);
CompletionStage<R> whenCompleteAsync(consumer);
CompletionStage<R> handle(fn);
CompletionStage<R> handleAsync(fn);

案例

     CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(Thread.currentThread().getName() + " 异步调用三方");
            try {
                Thread.sleep(TimeUnit.SECONDS.toSeconds(10));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 1;
        }).thenApply(f -> {
            return f + 10;
        }).whenComplete((v, e) -> {
            if (e == null) {
                System.out.println("计算结果为:" + v);
            }
        }).exceptionally(e -> {
            e.printStackTrace();
            return null;
        });

http://www.niftyadmin.cn/n/4935643.html

相关文章

谈谈传感器技术

目录 1.什么是传感器 2.传感器有哪些种类 3.传感器的应用领域 4.传感器对人类生活的影响 5.传感器技术未来的发展趋势 1.什么是传感器 传感器是一种能够感知外部环境和物理量的设备或组件。它们将物理量&#xff08;如温度、压力、湿度、光照、位置等&#xff09;转化为可…

【24择校指南】南京大学计算机考研考情分析

南京大学(A) 考研难度&#xff08;☆☆☆☆☆&#xff09; 内容&#xff1a;23考情概况&#xff08;拟录取和复试分数人数统计&#xff09;、院校概况、23初试科目、23复试详情、参考书目、各科目考情分析、各专业考情分析。 正文2178字&#xff0c;预计阅读&#xff1a;6分…

服务器数据恢复-断电导致ext4文件系统文件丢失的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器挂载一台存储设备&#xff0c;存储中划分一个Lun&#xff1b;服务器操作系统是Linux centos&#xff0c;EXT4文件系统。 服务器故障&分析&#xff1a; 意外断电导致服务器操作系统无法启动&#xff0c;系统在修复后可以正常启动&…

WPF 界面结构化处理

文章目录 概要一、xaml界面结构化处理二、逻辑树与视觉树 概要 WPF 框架是开源的&#xff0c;但是不能跨平台&#xff0c;可以使用MAUI&#xff0c;这个框架可以跨平台&#xff0c;WPF源码可以在github上下载&#xff0c;下载地址&#xff1a;https://gitbub.com/dotnet/wpf。…

案例:简易ATM

要求&#xff1a; 里面现存有100块钱如果存钱&#xff0c;就用输入钱加上先存的钱数&#xff0c;之后弹出显示余额提示框如果取钱&#xff0c;就减去取的钱数&#xff0c;之后弹出显示余额提示框如果显示余额&#xff0c;就输出余额如果退出&#xff0c;弹出退出信息提示框 代码…

centos7部署openldap开启memberof并接入jumpserver

文章目录 前言1.yum安装openldap2.配置密码3.导入配置4.定义域5.配置memberof6.配置base dn7.安装phpldapadmin管理8.调整httpd的配置9.调整php的配置10.登陆php管理页面11.同步旧ldapsever用户数据(可省略)12.客户端配置13.对接jumpserver 前言 介绍如何在centos7上部署openl…

8.1.tensorRT高级(3)封装系列-模型编译过程封装,简化模型编译代码

目录 前言1. 模型编译过程封装2. 问答环节总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-模型编译过程封装…

day6 STM32时钟与定时器

STM32时钟系统的概述 概念 时钟系统是由振荡器&#xff08;信号源&#xff09;、定时唤醒器、分频器等组成的电路。 常用的信号有晶体振荡器和RC振荡器。 意义 时钟是嵌入式系统的脉搏&#xff0c;处理器内核在时钟驱动下完成指令执行&#xff0c;状态变换等动作&#xff…