如何使用到期时间缓存单个

时间:2019-03-26 15:59:39

标签: rx-java reactive-programming rx-java2

我的计算代码繁重:

static class Computer {
    public Single<String> compute() {
        return Single.fromCallable(() -> {
            Thread.sleep(1000);
            System.out.println("Computation...");
            return "3.14";
        });
    }
}

我要对多个订阅者(即缓存)进行一次评估。

Computer computer = new Computer();
Single<String> c = computer.compute().cache();
c.blockingGet();
c.blockingGet();

但是我想让缓存在一定时间后过期:

Thread.sleep(2000);
//This should trigger computation
c.blockingGet();
c.blockingGet();

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

尝试了一段时间后,无法使用内置的Observable创建此设置。我认为这可能是可行的,但是IMO为此,您将需要Subject,对于这种特定设置,我认为这太过分了。

我发现的解决方案是为此创建一个自定义运算符,该运算符将自己为给定功能执行缓存超时。

该类如下所示:

class TimeoutSingleCache<Downstream, Upstream> implements SingleOperator<Downstream, Upstream> {

    private final Object LOCK = new Object();

    // Cache
    private long prevCallTime = -1;
    @Nullable
    private volatile Downstream cachedValue = null;

    // Inputs
    private final long invalidationTimeoutMillis;
    private final Function<Upstream, Downstream> operation;

    public TimeoutSingleCache(
            long invalidationTimeoutMillis,
            Function<Upstream, Downstream> operation
    ) {
        this.invalidationTimeoutMillis = invalidationTimeoutMillis;
        this.operation = operation;
    }

    @Override
    public SingleObserver<? super Upstream> apply(SingleObserver<? super Downstream> observer) throws Exception {
        return new SingleObserver<Upstream>() {

            @Override
            public void onSubscribe(Disposable d) {
                observer.onSubscribe(d);
            }

            @Override
            public void onSuccess(Upstream upstream) {
                long currentTime = System.currentTimeMillis();

                // Could be faster with double-check lock - not the point here
                synchronized (LOCK) {
                    if (cachedValue == null || prevCallTime + invalidationTimeoutMillis < currentTime) {
                        prevCallTime = currentTime;
                        try {
                            cachedValue = operation.apply(upstream);
                        } catch (Exception e) {
                            observer.onError(e);
                        }
                    }
                }

                observer.onSuccess(cachedValue);
            }

            @Override
            public void onError(Throwable e) {
                observer.onError(e);
            }
        };
    }
}

用法:

public static void main(String[] args) throws InterruptedException {
    Single<String> cachedComputation = Single.just(1)
            .lift(new TimeoutSingleCache<>(100L, input -> {
                System.out.println("Computation!");
                return "" + input + " : 3.14";
            }));

    System.out.println("1");
    System.out.println(cachedComputation.blockingGet());
    System.out.println("2");
    System.out.println(cachedComputation.blockingGet());
    Thread.sleep(200L);
    System.out.println("3");
    System.out.println(cachedComputation.blockingGet());
    System.out.println("4");
    System.out.println(cachedComputation.blockingGet());
}

输出:

1
Computation!
1 : 3.14
2
1 : 3.14
3
Computation!
1 : 3.14
4
1 : 3.14

希望有帮助。顺便问一句。