首页 > 解决方案 > 异步等待条件

问题描述

我想异步等待一个条件。下面是一个使用awaitility库的示例,但据我所知,awaitility它是阻塞的(即不是异步的)。关于如何以本机方式(或可能使用另一个库)以异步方式实现此目的的任何想法。任何想法表示赞赏。

await().forever().with().pollInterval(1, TimeUnit.SECONDS)
    .until(() -> redis.eval(lockscript, ScriptOutputType.BOOLEAN, "mutex:" + key).equals(true));
await().atMost(timeout, TimeUnit.SECONDS).with().pollInterval(1, TimeUnit.SECONDS).until(
    () -> redis.eval(lockscript, ScriptOutputType.BOOLEAN, "mutex:" + key).equals(true));

标签: javaasynchronous

解决方案


正如评论中提到的,您可以使用Completable FuturesScheduled Executor来获得您想要的东西(或者至少是接近的东西)。

我们可以until像这样定义一个方法:

public void until(Callable<Boolean> method, long timeout, TimeUnit unit, ScheduledExecutorService s) throws Exception {

    s.scheduleAtFixedRate(() -> {
        try {
            Boolean returnVal = method.call();
            if (returnVal == true)
                s.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }, timeout, timeout, unit);
}

这样做是接受一个传递scheduledExecutor并调用任何Callable方法(在这种情况下使用返回值Boolean,因为这是您想要的。这将循环每次timeout直到满足要求并且调度程序关闭。

注意:如果你想重用调度器,不要调用shutdown()它,而是cancel().

我们这样称呼它的方式如下:

ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
until(() -> basicBoolStatement(), 1, TimeUnit.SECONDS, sched);

我们不需要调度器拥有多个线程。只需传入任何其他返回布尔值的东西basicBoolStatement()

如果你想给你的请求一个时间限制,那么你可以做额外的电话,像这样:

public static void untilAtMost(Callable<Boolean> method, long untilTimeout, long atMostTimeout, TimeUnit unit, ScheduledExecutorService s) throws Exception {

    CompletableFuture.runAsync(() -> {
        try {
            until(method, untilTimeout, unit, s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
    
    ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
    sched.schedule(() -> {
        s.shutdown();
        sched.shutdown();
    }, atMostTimeout, unit);
}

在这里,我们重用了until上面的方法,但是我们有另一个调度器,它会shutdown()在时间过去until时执行调度器atMostTimeout

同样,调用代码看起来像:

ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
untilAtMost(() -> basicBoolStatement(), 10, 1, TimeUnit.SECONDS, sched);

编辑:如果您不想像处理Callable界面那样处理异常,您可以使用Supplier.

免责声明:对于混乱的代码感到抱歉,但这只是一个概念证明。


推荐阅读