CompletableFuture 对版本不同超时实现方案

5 篇文章 0 订阅
5 篇文章 1 订阅

CompletableFuture 是什么

CompletableFuture 是 Java 8 中引入的一个强大的异步编程工具。它是 Java 的 Future 接口的一个实现,提供了对异步计算的更多控制和更丰富的功能。CompletableFuture 的主要特点包括:

异步执行: CompletableFuture 可以异步执行任务,并在任务完成后通知调用者。这使得应用程序可以更好地利用多线程并发处理。

链式操作: CompletableFuture 提供了大量的方法来组合和转换异步任务,允许开发者以链式的方式编写复杂的异步流程。

错误处理: CompletableFuture 提供了错误处理的方法,可以在任务执行过程中捕获和处理异常。

时间控制: CompletableFuture (java9以及9以上)提供了超时和延时等方法,可以更好地控制异步任务的执行时间。

可组合性: CompletableFuture 可以与其他 Java 8 特性如 Stream 和 CompletionStage
等结合使用,提高代码的可读性和可维护性。

使用 CompletableFuture
可以帮助开发者编写更加简洁、易读和可维护的异步代码。它在处理许多并发任务、微服务调用、事件驱动架构等场景中都有广泛应用。

上面主要是CompletableFuture 的简单介绍今天我们主要针对他的超时场景做的分析以及不同版本实现的方案。
在我们业务场景中会使用CompletableFuture 提高并发处理但是我们假如有A和B 两个并发事件 A中出现死锁或者调用第三方接口超时、或者有其他导致线程一直无法释放的情况 这个时候调用CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();
会一直等待 特别我们高并发 线程直接拉满,影响整个系统稳定性。因此我们有必要做超时处理。

Java8 CompletableFuture 自定义实现超时方案

public class CompletableFutureTimeoutUtil {

    /**
     * 延迟类
     */
    static final class Delayer {


        static final class CompletableFutureDelaySchedulerFactory implements ThreadFactory {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setDaemon(true);
                t.setName("CompletableFutureDelaySchedulerFactory");
                return t;
            }
        }

        // 任务执行器
        static final ScheduledThreadPoolExecutor delayer;

        static {
            (delayer = new ScheduledThreadPoolExecutor(
                    1, new CompletableFutureTimeoutUtil.Delayer.CompletableFutureDelaySchedulerFactory())).
                    setRemoveOnCancelPolicy(true);
        }
    }

    /**
     * 通过ScheduledThreadPoolExecutor schedule定的延迟时间之后执行一次性任务
     *
     * @param timeout
     * @param unit
     * @param <T>
     * @return
     */
    public static <T> CompletableFuture<T> timeoutAfter(long timeout, TimeUnit unit) {
        CompletableFuture<T> result = new CompletableFuture<T>();
        CompletableFutureTimeoutUtil.Delayer.delayer.schedule(() -> result.completeExceptionally(new TimeoutException()), timeout, unit);
        return result;
    }

    /**
     * 使用 applyToEither 方法,将 future 和 timeoutFuture 两个 CompletableFuture 合并,谁先完成就使用谁的结果
     *
     * @param t        异常发生后返回默认值
     * @param future   参与执行的业务的任务
     * @param timeout  超时时间
     * @param unit     超时单位
     * @param runnable 函数接口  可以保存执行保存日志发送Mq 消息
     * @param <T>
     * @return
     */
    public static <T> CompletableFuture<T> completeOnTimeout(T t, CompletableFuture<T> future, long timeout, TimeUnit unit, Runnable runnable) {
        final CompletableFuture<T> timeoutFuture = timeoutAfter(timeout, unit);
        return future.applyToEither(timeoutFuture, Function.identity()).exceptionally((throwable) -> {
            Optional.ofNullable(runnable).ifPresent(Runnable::run);
            return t;
        });
    }
    }

大概思想就是通过ScheduledThreadPoolExecutor 线程延迟执行任务 实现和业务线程的对比applyToEither() 方法接收两个 CompletableFuture 作为参数,并将它们并行执行。当其中一个 CompletableFuture 先完成时,就会触发另一个 CompletableFuture 的回调函数。由此来实现延迟

实现代码测试

 private static void hasTimeOutAndError(List<CompletableFuture<String>> list) throws InterruptedException, ExecutionException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(2000);
                System.out.println("future");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int a = 10 / 0;
            return "ok";
        });
        CompletableFuture<String> completableFutureOne = CompletableFutureTimeoutUtil.completeOnTimeout("error", future, 1, TimeUnit.SECONDS, () -> System.out.println("log error 保存入库"));
        list.add(completableFutureOne);
        System.out.println("Test");
        CompletableFuture<String> futureStr = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(2000);
                System.out.println("futureStr");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "ok";
        });
        CompletableFuture<String> completableFutureTwo = CompletableFutureTimeoutUtil.completeOnTimeout("time out", futureStr, 1, TimeUnit.SECONDS, null);
        list.add(completableFutureTwo);
        CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();
        System.out.println(completableFutureOne.get());
        System.out.println(completableFutureTwo.get());
    }

    private static void allSuccess(List<CompletableFuture<String>> list) throws InterruptedException, ExecutionException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(2000);
                System.out.println("future");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "ok";
        });
        CompletableFuture<String> completableFutureOne = CompletableFutureTimeoutUtil.completeOnTimeout("error", future, 10, TimeUnit.SECONDS, () -> System.out.println("log error 保存入库"));
        list.add(completableFutureOne);
        System.out.println("Test");
        CompletableFuture<String> futureStr = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(2000);
                System.out.println("futureStr");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "ok";
        });
        CompletableFuture<String> completableFutureTwo = CompletableFutureTimeoutUtil.completeOnTimeout("time out", futureStr, 10, TimeUnit.SECONDS, null);
        list.add(completableFutureTwo);
        CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();
        System.out.println(completableFutureOne.get());
        System.out.println(completableFutureTwo.get());
    }

Java9 内置实现方案

Java9 内置底层也是利用ScheduledThreadPoolExecutor 实现。具体可以参考Java9以及以上版本CompletableFuture 代码

实现代码测试

private static void java9PlusTimeOutAndError(List<CompletableFuture<String>> list) throws InterruptedException, ExecutionException {
        CompletableFuture<String> completableFutureOne = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(1);
                System.out.println("completableFutureOne");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            int a = 9 / 0;
            return "completableFutureOne-ok";
        }).completeOnTimeout("error", 3, TimeUnit.SECONDS).exceptionally(ex -> {
            if (ex instanceof TimeoutException) {
                System.out.println("Timeout occurred!");
            } else if (ex instanceof CompletionException) {
                System.out.println("Task exception: " + ex.getCause().getMessage());
            } else if (ex instanceof RejectedExecutionException) {
                System.out.println("Task rejected: " + ex.getMessage());
            } else {
                System.out.println("Unknown exception: " + ex.getMessage());
            }
            return "fallback";
        });
        ;
        list.add(completableFutureOne);
        System.out.println("Test");
        CompletableFuture<String> completableFutureTwo = CompletableFuture.supplyAsync(() -> {
            try {
                sleep(2000);
                System.out.println("completableFutureTwo");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "completableFutureTwo-ok";
        }).completeOnTimeout("error", 1, TimeUnit.SECONDS);
        list.add(completableFutureTwo);
        CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();
        System.out.println(completableFutureOne.get());
        System.out.println(completableFutureTwo.get());
    }

测试

 public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        Stopwatch stopwatch = Stopwatch.createStarted();
        List<CompletableFuture<String>> list = Lists.newArrayList();
        java9PlusTimeOutAndError(list);
        stopwatch.stop();
        long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
        System.out.println("耗时:" + elapsed);
    }
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
CompletableFutureJava 8 引入的一个类,用于实现多线程的异步编程。它提供了丰富的方法来处理异步任务的结果、组合多个异步任务以及处理异常情况。 要实现超时处理,你可以结合 CompletableFuture 的方法和 Java 的 ScheduledExecutorService 来实现。下面是一个示例: ```java import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; public class CompletableFutureTimeoutExample { public static void main(String[] args) { // 创建一个 ScheduledExecutorService 用于超时处理 ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); // 创建一个 CompletableFuture 对象 CompletableFuture<String> future = new CompletableFuture<>(); // 设置超时时间 long timeout = 5000; // 5秒 // 在指定时间后取消 CompletableFuture executorService.schedule(() -> { if (!future.isDone()) { future.completeExceptionally(new TimeoutException("Timeout")); } }, timeout, TimeUnit.MILLISECONDS); // 异步任务 CompletableFuture.runAsync(() -> { try { // 执行异步操作,例如网络请求、数据库查询等 String result = performAsyncTask(); // 当任务完成时,设置结果给 CompletableFuture future.complete(result); } catch (Exception e) { future.completeExceptionally(e); } }); // 获取结果或处理超时异常 try { String result = future.get(); // 处理成功结果 } catch (TimeoutException e) { // 处理超时异常 } catch (InterruptedException | ExecutionException e) { // 处理其他异常 } // 关闭 ScheduledExecutorService executorService.shutdown(); } private static String performAsyncTask() { // 执行异步任务的逻辑 return "Async task result"; } } ``` 在上面的示例中,我们创建了一个 CompletableFuture 对象,并使用 ScheduledExecutorService 在指定的超时时间后取消 CompletableFuture。然后,我们使用 CompletableFuture.runAsync 方法执行异步任务,并在任务完成时设置结果给 CompletableFuture。最后,我们使用 future.get() 方法来获取结果或处理超时异常。 希望以上信息能够帮助到你!如果你还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛乌龟一起走

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值