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. 判断python socket服务端有没有关闭的方法

    通过 getattr(socket, '_closed') 的返回值可以判断服务端的运行状态. True 是关闭状态,False 是运行中. import socket ip = 'localhost ...

  2. LocalDateTime 使用记录

    1.LocalDateTime 获取指定日期的月初和月末 LocalDateTime firstDayTime = LocalDate.now().withMonth(12).withDayOfMon ...

  3. JS-变量存储

    1.存储(变量)JS中变量是存在栈内存中JS中的内存分两种:栈内存.堆内存 栈内存:存放变量 堆内存:存代码块(object和function) var fn=function()和function ...

  4. shell_Day03

    嗯,这是第二天,吧 wc word count 统计文本文件中的字符个数 -l 查看行数 -w 查看字符个数 -c 查看文件大小(字节)   cut 用来分割文件内容 -d 指定分隔符,delimit ...

  5. log4j2.xml配置全部正确,但是控制台不能输出错误日志

    如果配置文件,确定都没有问题,那么可能是Logger的包引入的不对: private static Logger logger = LogManager.getLogger(TrainControll ...

  6. 我常用的Linux快捷命令

    alias 设置快捷自定义命令 语法: alias 快捷命令='完整命令' 因为可以直接把上述当成一条语句来执行,但是服务器重启之后会失效,被称为临时快捷命令: 但是!将他写入 ~/.bashrc 文 ...

  7. c语言中printf不输出任何东西?,缓冲区未满不输出任何东西

    下面代码为什么没有任何输出: #include<cstdio> #include<unistd.h> int main(int argc, char **argv){ whil ...

  8. JAVA框架知识

    Java中的MVC: M是指模型层,C则是控制器,V是指视图:一个完整的请求过程是,客户端发送请求到控制器,控制器调用业务层处理请求,并返回处理结果给视图,其中业务层是调用Dao层去完成业务逻辑的:M ...

  9. AXI 协议翻译介绍

    一.介绍 Introduction 本章描述了axis协议的体系结构和协议定义的基本事务.它包含以下部分:•第1-2页关于AXI协议•第1-3页是架构•第1-7页是基本事务•第1-11页的附加功能. ...

  10. satpy 处理卫星 FY4A 数据

    读取数据并画图 import os import glob from datetime import datetime, timedelta from satpy.scene import Scene ...