为什么scheduleAtFixedRate - scheduleWithFixedDelay方法不使用Callable <v> </v>

时间:2014-07-29 18:15:10

标签: java java.util.concurrent

我正在做一些关于Java 8中并发性的实验

ScheduledThreadPoolExecutor API

我可以看到以下两个签名:

schedule(Callable<V> callable, long delay, TimeUnit unit)
schedule(Runnable command, long delay, TimeUnit unit)

一个用于Callable,另一个用于Runnable

我也可以在API中看到以下两个:

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

我的问题是,为什么不存在Callable

的两个等价物
scheduleAtFixedRate(Callable<V> callable, long initialDelay, long period, TimeUnit unit)
scheduleWithFixedDelay(Callable<V> callable, long initialDelay, long delay, TimeUnit unit)

我需要检索操作的布尔结果。

谢谢。

2 个答案:

答案 0 :(得分:15)

您期望scheduleAtFixedRate(Callable<V>)的返回类型是什么? schedule(Callable<V>)的返回类型为Future<V>,表示在将来的某个时刻,可调用返回的类型V的值将可用。您可以通过在Future上调用get()来等待此值。

scheduleAtFixedRate(Callable<V>)的返回类型不能像Future<List<V>>那样,因为这意味着在将来的某个时刻,重复调用返回的所有值可以调用。但是,将会有更多的可调用调度执行,因此该列表将永远不存在。

您需要的是这样的结果的异步流的概念,您可以按照这样的方式订阅,以便在到达时处理每个结果。据我所知,这在标准库中不存在。我知道的一个包含这样东西的第三方库是Netflix的RxJava。例如,使用该库中的ReplaySubject,您可以创建结果流并在返回结果时处理每个结果:

import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import rx.subjects.ReplaySubject;

public class Callables {

    public static void main(String[] args) {
        // Example Callable that returns a boolean result
        Random random = new Random();
        Callable<Boolean> callable = () -> random.nextBoolean();

        // Turn the Callable into a Runnable that adds the last result to the stream of results
        ReplaySubject<Boolean> results = ReplaySubject.create();
        Runnable runnable = () -> {
            try {
                boolean result = callable.call();
                results.onNext(result);
            } catch (Exception e) {
                // Needed since Callable can throw an exception, but Runnable cannot
            }
        };

        // Periodically run the Runnable
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
        executor.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);

        // Handling the results as they arrive
        results.forEach(result -> System.out.println("Result: " + result));

        System.out.println("Waiting for results...");
    }

}

如果你决定使用RxJava,可能值得使用更多的API,而不是直接使用Executor。您可以使用Observable.interval生成定期发出数字的流,然后将其映射以调用您的callable。这样,您可以更简洁的方式获得相同的结果流:

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import rx.Observable;

public class MoreCallables {

    public static void main(String[] args) throws IOException {
        Observable<Long> periodic = Observable.interval(1, TimeUnit.SECONDS);

        Random random = new Random();
        Observable<Boolean> results = periodic.map(i -> random.nextBoolean());

        results.forEach(result -> System.out.println("Result: " + result));

        System.out.println("Waiting for results...");
        System.in.read();
    }

}

答案 1 :(得分:0)

在@andersschuller解决方案之后,它可能看起来更简洁:

Observable.interval(1, TimeUnit.SECONDS)
    .map((Long i) -> "tick " + i)
    .forEach(result -> System.out.println("Result: " + result));