java8中CompletableFuture异步处理超时的方法

Java 8 的 CompletableFuture 并没有 timeout 机制,虽然可以在 get 的时候指定 timeout,但是我们知道get 是一个同步堵塞的操作。怎样让 timeout 也是异步的呢?Java 8 内有内建的机制支持,一般的实现方案是启动一个 ScheduledThreadpoolExecutor 线程在 timeout 时间后直接调用 CompletableFuture.completeExceptionally(new TimeoutException()),然后用 acceptEither() 或者 applyToEither 看是先计算完成还是先超时。

在 java 9 引入了 orTimeout 和 completeOnTimeOut 两个方法支持 异步 timeout 机制:

  • public CompletableFuture orTimeout(long timeout, TimeUnit unit) : completes the CompletableFuture with a TimeoutException after the specified timeout has elapsed.
  • public CompletableFuture completeOnTimeout(T value, long timeout, TimeUnit unit) : provides a default value in the case that the CompletableFuture pipeline times out.

内部实现上跟我们上面的实现方案是一模一样的,只是现在不需要自己实现了。

实际上hystrix等熔断的框架,其实现线程Timeout之后就关闭线程,也是基于同样的道理,所以我们可以看到hystrix中会有一个Timer Thread。

超时工具类

package com.example.netty.async;

import java.util.concurrent.*;
import java.util.function.Function; /**
* java8中CompletableFuture异步处理超时的方法
*
* Java 8 的 CompletableFuture 并没有 timeout 机制,虽然可以在 get 的时候指定 timeout,是一个同步堵塞的操作。怎样让 timeout 也是异步的呢?Java 8 内有内建的机
* 制支持,一般的实现方案是启动一个 ScheduledThreadpoolExecutor 线程在 timeout 时间后直接调用 CompletableFuture.completeExceptionally(new TimeoutException()),
* 然后用acceptEither() 或者 applyToEither 看是先计算完成还是先超时:
*
* 在 java 9 引入了 orTimeout 和 completeOnTimeOut 两个方法支持 异步 timeout 机制:
*
* public CompletableFuture orTimeout(long timeout, TimeUnit unit) : completes the CompletableFuture with a TimeoutException after the specified timeout has elapsed.
* public CompletableFuture completeOnTimeout(T value, long timeout, TimeUnit unit) : provides a default value in the case that the CompletableFuture pipeline times out.
* 内部实现上跟我们上面的实现方案是一模一样的,只是现在不需要自己实现了。
*
* 实际上hystrix等熔断的框架,其实现线程Timeout之后就关闭线程,也是基于同样的道理,所以我们可以看到hystrix中会有一个Timer Thread
*
*
* @author luliang
* @date 2021-02-24 9:48
*/
public class CompletableFutureTimeout {
/**
* Singleton delay scheduler, used only for starting and * cancelling tasks.
*/
static final class Delayer {
static ScheduledFuture<?> delay(Runnable command, long delay,
TimeUnit unit) {
return delayer.schedule(command, delay, unit);
} static final class DaemonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("CompletableFutureDelayScheduler");
return t;
}
} static final ScheduledThreadPoolExecutor delayer; // 注意,这里使用一个线程就可以搞定 因为这个线程并不真的执行请求 而是仅仅抛出一个异常
static {
(delayer = new ScheduledThreadPoolExecutor(
1, new CompletableFutureTimeout.Delayer.DaemonThreadFactory())).
setRemoveOnCancelPolicy(true);
}
} public static <T> CompletableFuture<T> timeoutAfter(long timeout, TimeUnit unit) {
CompletableFuture<T> result = new CompletableFuture<T>();
// timeout 时间后 抛出TimeoutException 类似于sentinel / watcher
CompletableFutureTimeout.Delayer.delayer.schedule(() -> result.completeExceptionally(new TimeoutException()), timeout, unit);
return result;
} /**
* 哪个先完成 就apply哪一个结果 这是一个关键的API,exceptionally出现异常后返回默认值
*
* @param t
* @param future
* @param timeout
* @param unit
* @param <T>
* @return
*/
public static <T> CompletableFuture<T> completeOnTimeout(T t, CompletableFuture<T> future, long timeout, TimeUnit unit) {
final CompletableFuture<T> timeoutFuture = timeoutAfter(timeout, unit);
return future.applyToEither(timeoutFuture, Function.identity()).exceptionally((throwable) -> t);
} /**
* 哪个先完成 就apply哪一个结果 这是一个关键的API,不设置默认值,超时后抛出异常
*
* @param t
* @param future
* @param timeout
* @param unit
* @param <T>
* @return
*/
public static <T> CompletableFuture<T> orTimeout(T t, CompletableFuture<T> future, long timeout, TimeUnit unit) {
final CompletableFuture<T> timeoutFuture = timeoutAfter(timeout, unit);
return future.applyToEither(timeoutFuture, Function.identity()).exceptionally((throwable) -> t);
}
}

测试类

package com.example.netty.async;

import java.util.concurrent.*;

/**
* @author luliang
* @date 2021-02-24 10:05
*/
public class CompletableFutureTimeout2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
}); CompletableFuture<Integer> within = CompletableFutureTimeout.completeOnTimeout(1, future, 1, TimeUnit.SECONDS);
System.out.println(within.get()); CompletableFuture<String> futureStr = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "正常执行";
}); CompletableFuture<String> withinStr = CompletableFutureTimeout.completeOnTimeout("异常执行", futureStr, 1, TimeUnit.SECONDS);
System.out.println(withinStr.get()); }
}

java8中CompletableFuture异步处理超时的更多相关文章

  1. java8中CompletableFuture的使用介绍

    既然CompletableFuture类实现了CompletionStage接口,首先我们需要理解这个接口的契约.它代表了一个特定的计算的阶段,可以同步或者异步的被完成.你可以把它看成一个计算流水线上 ...

  2. Dubbo中CompletableFuture异步调用

    使用Future实现异步调用,对于无需获取返回值的操作来说不存在问题,但消费者若需要获取到最终的异步执行结果,则会出现问题:消费者在使用Future的get()方法获取返回值时被阻塞.为了解决这个问题 ...

  3. Java8系列 (七) CompletableFuture异步编程

    概述 Java8之前用 Future 处理异步请求, 当你需要获取任务结果时, 通常的做法是调用  get(long timeout, TimeUnit unit) 此方法会阻塞当前的线程, 如果任务 ...

  4. Java CompletableFuture 异步超时实现探索

    作者:京东科技 张天赐 前言 JDK 8 是一次重大的版本升级,新增了非常多的特性,其中之一便是 CompletableFuture.自此从 JDK 层面真正意义上的支持了基于事件的异步编程范式,弥补 ...

  5. 使用 CompletableFuture 异步组装数据

    使用 CompletableFuture 异步组装数据 一种快捷.优雅的异步组装数据方式 实际项目中经常遇到这种情况: 从多个表中查找到数据然后拼装成一个VO返回给前端. 这个过程有可能会非常耗时.因 ...

  6. jdk8中CompletableFuture的各个API用法,极大扩展了Future

    就不介绍了,直接贴代码,建议在代码中使用,真的很方便 package cn.hou.completablefuture; import org.junit.Test; import java.util ...

  7. Netty 中的异步编程 Future 和 Promise

    Netty 中大量 I/O 操作都是异步执行,本篇博文来聊聊 Netty 中的异步编程. Java Future 提供的异步模型 JDK 5 引入了 Future 模式.Future 接口是 Java ...

  8. .Net中的异步编程总结

    一直以来很想梳理下我在开发过程中使用异步编程的心得和体会,但是由于我是APM异步编程模式的死忠,当TAP模式和TPL模式出现的时候我并未真正的去接纳这两种模式,所以导致我一直没有花太多心思去整理这两部 ...

  9. HttpApplication中的异步线程

    一.Asp.net中的线程池设置 在Asp.net的服务处理中,每当服务器收到一个请求,HttpRuntime将从HttpApplication池中获取一个HttpApplication对象处理此请求 ...

  10. PHP中实现异步调用多线程程序代码

    本文章详细的介绍了关于PHP中实现异步调用多线程方法,下面我们以给1000个用户发送一封推荐邮件,用户输入或者导入邮件账号了提交服务器执行发送来讲述. 比如现在有一个场景,给1000个用户发送一封推荐 ...

随机推荐

  1. 一套 .NET开发的邮箱Mail开源库

    今天给大家推荐一个基于.Net开发的邮箱开源库. 邮箱在我们日常工作中,可以说是非常常见了.个人邮箱一般都是免费的,但企业邮箱会收费,虽然一般情况下,市面邮箱已经够用了.但有些企业对内容安全要求比较严 ...

  2. wget 多线程下载 mwget 工具安装

    # for centos mini #yum -y install gcc-c++ intltool libssl-dev yum -y install gcc-c++ intltool openss ...

  3. usb 2.0 high speed resetting signaling.

  4. 大小写字符转换【Sql Server和C#两种写法】

    案例:Var Str = "abdCnd" 如何将Str = "ABDCND"? Sql Server写法:upper(Str)   ==>  Lower ...

  5. libnode使用addon

    自己编译的一个libnode.so后,在js里调用hello.node的 addon时候会报错. Error: dlopen failed: cannot locate symbol "na ...

  6. VMWARE 虚拟机配置优化

    如果硬件性能不足,可做如下优化. 1.禁用 VMWARE  虚拟内存功能. 编辑->首选项-> 内存  , 设置如下,禁用内存交换. 2. 如果虚拟机装在机械盘,而电脑有固太硬盘,可通过 ...

  7. C语言学习记录(一)

    C语言学习记录(一) 一.知识要点(程序设计概述) 1.程序与程序设计语言 概念:程序就是给计算机下一系列指令,使其完成任务.而编写这些指令就是程序设计. 程序设计语言 第一代程序设计语言(1GL): ...

  8. 双CAN通讯模板

    本文中CAN1采用16位掩码,CAN2只能使用大于等于14的筛选器组,根据手册只能使用32位的掩码(因为大于14的筛选器没有说明). 经测试,STM32手册中的筛选器配置图错误,库函数的命名正确.参考 ...

  9. Vue + Element table中的某行触发enter事件后,使该行disabled

    废话不罗嗦,上硬菜. 1.html下: <el-table-column label="名称" sortable> <template slot-scope=&q ...

  10. ubuntu 16.04 安装peach

    当前操作系统:ubuntu 16.04 使用 TUNA 的软件源镜像替换sources.list 备份原sources.list文件 sudo cp /etc/apt/sources.list /et ...