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. PHP_工厂模式

    实例化类,先需要引入类文件,但是有时候我们并不知道可能要用到那些类,如果将所有类文件全部引入,会造成资源浪费,这时候可以采用工厂模式,专门用于 自动加载.实例化 类. 实例代码: 注:案例中假设有一个 ...

  2. CCIE DC Multicast Part 3.

    Hi Guys! Here is part 3 of the Multicast Tutorials, Hopefully you have read the two previous posts h ...

  3. 5G工业智能网关助力智能制造开辟新赛道

    今年以来,物联网技术加速产业变革,制造业出现了不少新现象.从大规模到个性化.从"渠道为王"到"用户定义".从自有工厂到共享协同,智能化制造在很多地方颠覆了传统模 ...

  4. 记录multipartFile表单类型转化为file

    导入依赖 <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</a ...

  5. C#开发上位机常用

    从深圳回内地几年了,突然想把之前项目中用到的东西做信合集,别忘记了!!!

  6. 复杂SQL语句及其优化

    一,复杂SQL语句类型 1 ,笛卡尔连接 题目1:找出工资超过各自经理的员工姓名 表:employee(id , name , depid , salary, manager_id ) SELECT ...

  7. kali上的apache2

    之前总是疑惑为什么kali上的apache服务称之为apache2,但是也没想到去找找答案,今天突然想到了,简单搜索了一下大致就是, 现在Apache HTTP 存在三种版本, 1.3 2.0 和2. ...

  8. MQTT QoS 0, 1, 2 介绍

    什么是 QoS 很多时候,使用 MQTT 协议的设备都运行在网络受限的环境下,而只依靠底层的 TCP 传输协议,并不能完全保证消息的可靠到达.因此,MQTT 提供了 QoS 机制,其核心是设计了多种消 ...

  9. 项目开发中的ORM框架使用mybatis还是mybatis-plus

    mybatis支持xml配置文件和注解 mybaits-plus也支持xml配置文件和注解,多了baseMapper,将基础的CRUD操作单独拿出来进行了封装 mybatis是一款优秀的持久层框架,它 ...

  10. JS实现复制富文本到剪贴板/粘贴板的最佳实践

    背景 最近有想实现一个功能,通过点击一个button按钮,来复制网页内容(含html)来实现复制后粘贴到邮件或者word具有富文本的效果.在网站翻了一些资料,要么就是方法已经被弃用,要么就是兼容性特别 ...