异步http 超时_具有CompletableFuture的异步超时

异步http 超时

有一天,我重写了执行不佳的多线程代码,该代码在Future.get()某个时刻被阻塞:

public void serve() throws InterruptedException, ExecutionException, TimeoutException {final Future<Response> responseFuture = asyncCode();final Response response = responseFuture.get(1, SECONDS);send(response);
}private void send(Response response) {//...
}

这实际上是一个用Java编写的Akka应用程序,具有1000个线程的线程池(原文如此!)–所有这些线程都在此get()调用中被阻止。 否则系统无法跟上并发请求的数量。 重构后,我们摆脱了所有这些线程,只引入了一个,大大减少了内存占用。 让我们简化一下并显示Java 8中的示例。第一步是引入CompletableFuture而不是普通的Future (请参阅提示9 )。 很简单,如果:

  • 您可以控制如何将任务提交给ExecutorService :只需使用CompletableFuture.supplyAsync(..., executorService)而不是executorService.submit(...)
  • 您处理基于回调的API:使用Promise

否则(如果您已经阻塞了API或Future<T> ),将有一些线程被阻塞。 这就是为什么现在有这么多异步API诞生的原因。 假设我们以某种方式重写了代码以接收CompletableFuture

public void serve() throws InterruptedException, ExecutionException, TimeoutException {final CompletableFuture<Response> responseFuture = asyncCode();final Response response = responseFuture.get(1, SECONDS);send(response);
}

显然,这并不能解决任何问题,我们必须利用新的React式编程风格:

public void serve() {final CompletableFuture<Response> responseFuture = asyncCode();responseFuture.thenAccept(this::send);
}

这在功能上是等效的,但现在serve()应该立即运行(没有阻塞或等待)。 只要记住, this::send将在完成responseFuture的同一线程中执行。 如果您不想在某个地方重载某些任意线程池或send()昂贵,请考虑为此使用单独的线程池: thenAcceptAsync(this::send, sendPool) 。 很好,但是我们失去了两个重要的属性:错误传播和超时。 因为我们更改了API,所以错误传播很难。 当serve()方法退出时,异步操作可能尚未完成。 如果您关心异常,请考虑返回responseFuture或其他替代机制。 至少,请记录异常,因为否则它将被吞噬:

final CompletableFuture<Response> responseFuture = asyncCode();
responseFuture.exceptionally(throwable -> {log.error("Unrecoverable error", throwable);return null;
});

请注意上面的代码: exceptionally()尝试从故障中恢复 ,并返回替代结果。 它在这里有效,但是如果您将thenAccept() exceptionally()thenAccept() ,即使发生故障也将调用send() ,但使用null参数(或者我们从exceptionally()返回的值exceptionally()

responseFuture.exceptionally(throwable -> {log.error("Unrecoverable error", throwable);return null;}).thenAccept(this::send);  //probably not what you think

丢失1秒超时的问题非常微妙。 我们的原始代码等待(阻塞)最多1秒钟,直到Future完成。 否则抛出TimeoutException 。 我们失去了此功能,甚至超时的更糟糕的单元测试也不方便并且经常被跳过。 为了在不牺牲事件驱动精神的前提下实现超时,我们需要一个额外的构建块:在给定时间之后始终失败的未来:

public static <T> CompletableFuture<T> failAfter(Duration duration) {final CompletableFuture<T> promise = new CompletableFuture<>();scheduler.schedule(() -> {final TimeoutException ex = new TimeoutException("Timeout after " + duration);return promise.completeExceptionally(ex);}, duration.toMillis(), MILLISECONDS);return promise;
}private static final ScheduledExecutorService scheduler =Executors.newScheduledThreadPool(1,new ThreadFactoryBuilder().setDaemon(true).setNameFormat("failAfter-%d").build());

这很简单:我们创建一个诺言 (没有基础任务或线程池的未来),并在给定java.time.Duration之后使用TimeoutException完成它。 如果您get()某个地方get()这样的未来,则阻塞至少这么长时间后,将抛出TimeoutException 。 实际上,它将是ExecutionException包装TimeoutException ,没有办法解决。 请注意,我仅使用一个线程使用固定scheduler线程池。 这不仅是出于教育目的:“在这种情况下,“ 1个线程对于任何人都应该足够 ”” [1]failAfter()本身是没有用的,但将其与我们的responseFuture结合起来,我们就有了解决方案!

final CompletableFuture<Response> responseFuture = asyncCode();
final CompletableFuture<Response> oneSecondTimeout = failAfter(Duration.ofSeconds(1));
responseFuture.acceptEither(oneSecondTimeout, this::send).exceptionally(throwable -> {log.error("Problem", throwable);return null;});

这里发生了很多事情。 在通过我们的后台任务接收到responseFuture ,我们还创建了一个“合成的” oneSecondTimeout未来,它将永远不会成功完成,但总是在1秒后失败。 现在,我们通过调用acceptEither合并两者。 该运算符将针对第一个完成的将来( responseFutureoneSecondTimeout执行代码块,而只是忽略较慢的代码的结果。 如果asyncCode()在1秒钟内完成,则会调用this::send并且oneSecondTimeout异常将被忽略。 然而! 如果asyncCode()确实很慢,则oneSecondTimeout启动。 但是由于失败并带有异常,因此将调用exceptionally错误处理程序,而不是this::send 。 您可以认为send()exceptionally将被调用,而不是两者都被调用。 当然,如果我们有两个正常完成的“普通”期货,则将以第一个的响应调用send() ,并丢弃后者。

这不是最干净的解决方案。 一个干净的人会包装原始的未来,并确保它在给定的时间内完成。 此类运算符可在com.twitter.util.Future (Scala;称为com.twitter.util.Futurewithin() )中使用,但是在scala.concurrent.Future丢失(可能是受前者启发)。 让我们留下Scala并为CompletableFuture实现类似的运算符。 它以一个Future作为输入,并返回一个在基础底层完成时完成的Future。 但是,如果完成基础的未来花费的时间太长,则会引发异常:

public static <T> CompletableFuture<T> within(CompletableFuture<T> future, Duration duration) {final CompletableFuture<T> timeout = failAfter(duration);return future.applyToEither(timeout, Function.identity());
}

这导致了最终,清洁和灵活的解决方案:

final CompletableFuture<Response> responseFuture = within(asyncCode(), Duration.ofSeconds(1));
responseFuture.thenAccept(this::send).exceptionally(throwable -> {log.error("Unrecoverable error", throwable);return null;});

希望您喜欢这篇文章,因为您可以看到Java的React式编程已不再是未来的事情(无双关)。

翻译自: https://www.javacodegeeks.com/2014/12/asynchronous-timeouts-with-completablefuture.html

异步http 超时

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/338564.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言指针变量与一维数组

数组元素之间的地址是相连的&#xff1b;变量地址绝对不是相连的&#xff0c;如果找到规律那也只是一个偶然的&#xff0c;不是必然的&#xff1b;1. 指针变量和一位数组下面对指针数组进行分析&#xff0c;index(小标是从0开始)&#xff0c;array数组是int类型&#xff0c;每一…

天干地支计算公式_高大上:天干地支计算方法

天干地支是我国古代计算年月日的重要依据&#xff0c;作为现代人的我们&#xff0c;有必要去了解一下&#xff0c;他们&#xff0c;以备不时之需。首先介绍一下&#xff0c;天干和地支。共有十天干和十二地支。十天干&#xff1a;甲(jiǎ)、乙(yǐ)、丙(bǐng)、丁(dīng)、戊(…

input发送a.jax_JAX-RS 2.0:服务器端处理管道

input发送a.jax这篇文章的灵感来自JAX-RS 2.0规范文档 &#xff08;附录C&#xff09;中的Processing Pipeline部分。 我喜欢它的原因在于它提供了JAX-RS中所有模块的漂亮快照-以准备好吞咽的胶囊形式&#xff01; 礼貌– JAX-RS 2.0规范文档 因此&#xff0c;我想到了使用此…

html 登录失败,qq音乐登录失败 QQ音乐总是显示登录失败是怎么回事

urlproc.exe是什么进程?没见过&#xff0c;请前辈们指点&#xff1f;造成QQ音乐登录不上现象的原因有如下三种可能&#xff1a; 一、木马病毒对QQ音乐的必要组件或文件进行破坏&#xff0c;导致QQ音乐登录失败&#xff0c;登陆不上的情况发生。 二、Windows系统防火墙(或其他安…

C 常对象成员

C 常对象成员在C 中&#xff0c;可以将对象的成员声明为const&#xff0c;包括常数据成员和常成员函数C 常数据成员 常数据成员的作用与一般常变量相似&#xff0c;用关键字const来声明常数据成员。常数据成员的值是不能改变的&#xff0c;只能通过构造函数的参数初始化表对常数…

python gitlab_Python Gitlab Api 使用方法

简述公司使用gitlab 来托管代码,日常代码merge request 以及其他管理是交给测试&#xff0c;鉴于操作需经常打开网页,重复且繁琐,所以交给Python 管理。安装pip install python-gitlab环境: py3DEMO# -*- coding: utf-8 -*-__Author__ "xiewm"__Date__ 2017/12/26 …

tomee_Apache TomEE + JMS。 从未如此简单。

tomee我记得J2EE &#xff08;1.3和1.4&#xff09;的过去&#xff0c;使用JMS启动项目非常困难。 您需要安装JMS 代理 &#xff0c;创建主题或队列 &#xff0c;最后使用服务器配置文件和JNDI开始自己的战斗。 感谢JavaEE 6及其它&#xff0c;使用JMS确实非常简单。 但是&…

娄底二中高考2021成绩查询,2021年娄底高考状元名单公布,娄底高考状元学校资料及最高分...

2019年高考已经落下帷幕&#xff0c;高考放榜时刻就要到来&#xff0c;每年的高考状元都会被各界高度关注&#xff0c;那么今年娄底高考状元花落谁家呢&#xff1f;娄底高考状元会给人带来惊喜吗&#xff0c;让我们一起期待2019年娄底高考状元的诞生。下面小编为给为梳理下历年…

C 常指针

C 指向对象的常指针C 定义指向对象的常指针的一般形式为 类名 * const指针变量名&#xff1b;也可以在定义指针变量时使之初始化在C 中&#xff0c;虽然指向对象的常指针变量的值不能改变&#xff0c;但可以改变其所指向对象的值&#xff0c;如果想将一个指针变量固定地与一个对…

microsoftexchange邮箱容量怎样看_企业邮箱申请注册的要求有哪些?_网站建设_创客网络...

随着现在互联网信息化发展的速度不断加快&#xff0c;企业邮箱作为企业之间信息传输的重要工具&#xff0c;其重要性不亚于企业网站&#xff0c;但市场上企业邮箱种类繁多&#xff0c;包含的功能也各不相同&#xff0c;稍有差异&#xff0c;你知道怎么去选择好企业邮箱吗&#…

java 登陆验证失败_使用Java 8流进行快速失败的验证

java 登陆验证失败我已经失去了看过使用快速失败验证代码状态的代码的次数&#xff0c;方法如下&#xff1a; public class PersonValidator {public boolean validate(Person person) {boolean valid person ! null;if (valid) valid person.givenName ! null;if (valid) v…

Unity中Shader观察空间推导(在Shader中实现)

文章目录 前言一、观察空间矩阵推导1、求观察空间基向量2、求观察空间的基向量在世界空间中的矩阵 的 逆矩阵2、求平移变换矩阵3、相乘得出 观察空间转化矩阵4、得到顶点的世界空间坐标&#xff0c;然后转化到观察空间5、把观察空间坐标转化为齐次裁剪坐标输出到屏幕 二、最终效…

计算机应用技术一级考试成绩,《计算机应用基础》课程与等级考试成绩的关系...

《闽南师范大学关于计算机应用基础课程成绩的暂行规定》(闽南师大〔2016〕197号)已于2016年7月12日下发&#xff0c;但在执行过程总有包括教务员及学生在内各种人员的种种疑问及错误理解与传达&#xff0c;现在梳理如下&#xff1a;一、开设有《计算机应用基础》课程的学生&…

C 常引用

C 对象常引用在C 中&#xff0c;常用常指针和常引用作函数参数&#xff0c;既能保证数据安全&#xff0c;使数据不能被随意修改&#xff0c;在调用函数时又不必建立实参的拷贝。用常指针和常引用作函数参数&#xff0c;可以提高程序运行效率。在C 中&#xff0c;如果变量名和引…

jasonencode php_PHP的json_encode()函数与JSON对象

一、问题描述这周搬砖的时候&#xff0c;前端通过ajax获取后端的数据后&#xff0c;照例用 对象.属性 的方式取值&#xff0c;然而结果总是总是不能如预期般展示在页面上。先写个 demo 还原下场景&#xff1a;选中一个下拉框列表选项后&#xff0c;会在下拉框下面展示文字。这是…

intext:企业_企业中的微服务:敌是友?

intext&#xff1a;企业宏观问题的微观解决方法&#xff1f; 微服务的炒作无处不在&#xff0c;尽管业界似乎无法就确切的定义达成共识&#xff0c;但我们一再被告知&#xff0c;从单一应用程序转向由小型服务组成的面向服务的体系结构&#xff08;SOA&#xff09;是正确的方法…

mui hello html5 安装,HBuilder开发App Step1——环境搭建,HelloMUI 以及真机调试(示例代码)...

No1. 必须搭建java环境只需要最基础的java环境&#xff0c;也就是cmd下可以运行java和javac即可&#xff0c;具体教程请自行百度&#xff0c;都会有很详细的教程&#xff0c;这里不重点介绍。No2. 下载安装HBuilder下载完成后请将zip包解压缩到自定义的目录(windows)&#xf…

C 析构函数

C 析构函数概述C 析构函数是一个特殊的成员函数&#xff0c;作用与构造函数相反&#xff0c;它的名字是类名的前面加一个&#xff5e;符号&#xff0c;析构函数是与构造函数作用相反的函数&#xff0c;当对象的生命期结束时&#xff0c;会自动执行析构函数。C 执行析构函数的情…

前后端分离的项目部署到tomcat_前后端分离后,tomcat服务器部署和发布

打包服务端&#xff1a;IDEA打开项目&#xff0c;等待项目初始化完成&#xff0c;点击Build- Build Artifacts&#xff0c;进行打包image.png点击之后会出现下面这个小窗口&#xff0c;选择红框中部分&#xff1a;image.png这个过程就是打包了&#xff0c;等待打包完成之后&…

vue 侦听器侦听对象属性_不删除侦听器–使用ListenerHandles

vue 侦听器侦听对象属性听一个可观察的实例并对它的变化做出React很有趣。 做一些必要的事情来打断或结束这种聆听会变得很有趣。 让我们看看问题的根源和解决方法。 总览 这篇文章将首先讨论这种情况&#xff0c;然后再讨论常见的方法和问题所在。 然后&#xff0c;它将提供解…