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. Jenkins+Git+Gitlab+Ansible 持续集成和自动部署

  2. 读取excel等文件根据注解自动装填为实体类

    问题:以前每次读取excel 都是根据第几列来装填实体类里面的属性.写起来很麻烦.还要判断. 思路: 1.因为每次读取excel 或者word表格 都能得到是第几列的数据,那么可以知道每列数据的ind ...

  3. 20203412马畅若《Python程序设计》实验四Python综合实践报告

    作为初次接触程序设计的我在看到云班课中用python进行游戏编程后感到很有意思,所以我决定这次做一个最经典的小鸟管道游戏.虽然网上许多大佬都说这是最基础的一项游戏编码,但我还是用了许多时间去做成这个游 ...

  4. Robot-Framework 基础操作和常用的语法

    1.打开浏览器 Open Browser 2.浏览器最大化 Maximize Browser Window 3.关闭浏览器 Test Teardown Close Browser 4.输入文本框  I ...

  5. webpack和source map

    当 webpack 打包源代码时,可能会很难追踪到 error(错误) 和 warning(警告) 在源代码中的原始位置. 如果打包后代码有一处错误,特别是使用的vue.react这些前端框架.打包后 ...

  6. 基于winds10 安装docker 踩坑记录

    1.官方下载 https://www.docker.com/ 2.根据提示安装 并重庆计算机3.双击运行 报 Docker Desktop is shutting down 提示  计算机c: 盘 A ...

  7. postman脚本语法大全,不包括插件语法

    官方语法例子:https://learning.postman.com/docs/writing-scripts/script-references/test-examples/ 官方语法库:http ...

  8. save an excel csv to a github csv file

    :%s/\t/,/g

  9. noi 1.5 42画矩形

    noi 1.5 42画矩形 1.描述 根据参数,画出矩形. 2.输入 输入一行,包括四个参数:前两个参数为整数,依次代表矩形的高和宽(高不少于3行不多于10行,宽不少于5列不多于10列):第三个参数是 ...

  10. win10格式化U盘提示没有权限执行此操作

    解决办法参考:http://www.tpbz008.cn/post/766.html 1.gpedit.msc 2.展开计算机配置,管理模板.展开系统.选中可移动存储访问 3.所有可移动存储类:拒绝所 ...