简体   繁体   English

具有已过去时间信息的CompletableFuture

[英]CompletableFuture with elapsed time information

I need to have access to information about asynchronouos method execution time. 我需要访问有关asynchronouos方法执行时间的信息。 So, I'm trying to extend CompletableFuture functionality. 因此,我正在尝试扩展CompletableFuture功能。 Here is my implementation with decorator pattern usage: 这是我使用装饰器模式的实现:

import java.util.concurrent.*;
import java.util.function.*;
import static lombok.AccessLevel.PRIVATE;
import lombok.AllArgsConstructor;
import lombok.experimental.Delegate;

@AllArgsConstructor(access = PRIVATE)
public class ContinuousCompletableFuture<T> extends CompletableFuture<T> {

    @Delegate
    private final CompletableFuture<T> baseFuture;

    private final long creationTime;

    public static <U> ContinuousCompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return new ContinuousCompletableFuture<>(CompletableFuture.supplyAsync(supplier));
    }

    private ContinuousCompletableFuture(CompletableFuture<T> baseFuture) {
        this.baseFuture = baseFuture;
        this.creationTime = System.nanoTime();
    }

    public Long getElapsedTime() {
        return (System.nanoTime() - creationTime) / 1000_000L;
    }

    public ContinuousCompletableFuture<Void> thenAcceptAsync(BiConsumer<? super T, Long> action) {
        CompletionStage<Long> elapsedTime = CompletableFuture.completedFuture(getElapsedTime());
        return new ContinuousCompletableFuture<>(baseFuture.thenAcceptBothAsync(elapsedTime, action), creationTime);
    }
}

First test shouldReturnElapsedTime with extracted ContinuousCompletableFuture variable works fine, but other shouldOperateWithOwnExecutionTime fails. 使用提取的ContinuousCompletableFuture变量进行的第一个测试shouldReturnElapsedTime可以正常工作,但是其他shouldOperateWithOwnExecutionTime失败。 Meanwhile, I prefer to see it in my future code neither extracted ContinuousCompletableFuture variable. 同时,我更希望在以后的代码中看到它既未提取ContinuousCompletableFuture变量。

import java.util.concurrent.atomic.AtomicLong;
import lombok.extern.slf4j.Slf4j;
import org.junit.*;
import static org.junit.Assert.*;

@Slf4j
public class ContinuousCompletableFutureTest {

    private static final int DELAY = 1000;

    AtomicLong flag = new AtomicLong();

    ContinuousCompletableFuture<String> future;

    @Before
    public void before() {
        future = ContinuousCompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(DELAY);
            } catch (InterruptedException ex) {
                log.error("Error during ContinuousCompletableFuture execution", ex);
            }
            return "successfully completed";
        });
    }

    @Test
    public void shouldReturnElapsedTime() {
        future.thenAcceptAsync(s -> {
            long t = future.getElapsedTime();
            log.info("Elapsed {} ms to receive message \"{}\"", t, s);
            flag.set(t);
        });

        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            log.error("Error awaiting Test completion", ex);
        }

        assertTrue("Future completion should be delayed", flag.get() >= 0.75 * DELAY);
    }

    @Test
    public void shouldOperateWithOwnExecutionTime() {
        future.thenAcceptAsync((s, t) -> {
            log.info("Elapsed {} ms to receive message \"{}\"", t, s);
            flag.set(t);
        });

        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            log.error("Error awaiting Test completion", ex);
        }

        assertTrue("Future completion should be delayed", flag.get() >= 0.75 * DELAY);
    }
}

I assume that my issue lies in wrong thenAcceptBothAsync method usage. 我认为我的问题出在错误的thenAcceptBothAsync方法用法上。

Any suggestions? 有什么建议么?

In your method 用你的方法

public ContinuousCompletableFuture<Void> thenAcceptAsync(
                                         BiConsumer<? super T, Long> action) {
    CompletionStage<Long> elapsedTime=CompletableFuture.completedFuture(getElapsedTime());
    return new ContinuousCompletableFuture<>(
        baseFuture.thenAcceptBothAsync(elapsedTime, action), creationTime);
}

you are evaluating getElapsedTime() immediately and pass the result to the BiConsumer unchanged, regardless of the actual completion time. 您将立即评估getElapsedTime()并将结果不变地传递给BiConsumer ,而不管实际的完成时间如何。

You can fix it by querying the elapsed time right in the consumer: 您可以通过查询使用者中的经过时间来解决此问题:

public ContinuousCompletableFuture<Void> thenAcceptAsync(
                                         BiConsumer<? super T, Long> action) {
    return new ContinuousCompletableFuture<>(
        baseFuture.thenAcceptAsync(t -> action.accept(t, getElapsedTime())), creationTime);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM