使用 java 期货而不需要本地可变状态

Using java futures without requiring local mutable state

我编写了一些代码,主要负责通过我提供给客户的名为 "orchestrate" 的库方法按顺序编排多个 API(是的,我知道它很原始).这个编排方法背后的无非是一个循环,它按照收到的顺序执行 API,然后将其委托给许多 classes,其中包含一些用于构建的业务逻辑请求,调用 API,对响应执行一些验证并最终返回 api 结果。因此,如果客户端发送 api 列表: {a1, a2, a3, a4, a5} 它将以完全阻塞的方式依次执行每个 api。

我正在尝试将其加强到可以并行调用多个 API 的位置,具体取决于我从客户接收指令的方式。把它想象成客户向我发送一个列表列表,如:{ {a1, a2}, {a3}, {a4, a5} } 这意味着我想并行执行 a1 和 a2(这意味着构建他们的请求,调用 apis,验证响应)。然后等到我确定他们都完成了。然后执行a3,等我确定完成了。最后我想执行 a4 和 a5 并遵循通常的模式。

现在,我很想使用 futures 作为它们提供的简单抽象来执行方法,等待使用 .get() 方法的响应。但是我注意到 executorService 需要的是 future 对 call() 方法的调用。这很好,但让我觉得每个 class 实现的 call() 方法可能需要访问 "local" 数据才能完成它的工作(毕竟,我不能通过call() 方法任何特定参数)。我真的想避免持有任何本地可变状态,因为这会带来自己的副作用。

有没有办法让我不持有本地状态,仍然使用期货来处理我的多线程用例?还是我对期货的理解完全错误,我遗漏了一些明显的东西?如果没有,是否有关于一些替代方案的好的前进道路的建议?

好的,所以你有一个 class 它以阻塞的方式从网页获取一些数据,并接受一些参数:

public class DataFetcher {
    public Data fetchData(int param1, int param2) {
        // ...
    }
}

现在你想同时执行这个方法两次,然后取回期货。所以你只需要创建一个 Callable:

final DataFetcher fetcher = new DataFetcher();
Callable<Data> task1 = new Callable<>() {
    @Override
    public Data call() {
        return fetcher.fetchData(1, 2);
     }
};
Callable<Data> task2 = new Callable<>() {
    @Override
    public Data call() {
        return fetcher.fetchData(3, 4);
     }
};

Future<Data> result1 = executorService.submit(task1);
Future<Data> result2 = executorService.submit(task2);

我在这里没有看到任何可变状态。

为了避免重复代码和使用匿名classes,你可以定义一个顶层class:

public DataFetcherTask implements Callable<Data> {

    private final DataFetcher fetcher;
    private final int param1;
    private final int param2;

    public DataFetcherTask(DataFetcher fetcher, int p1, int p1) {
        this.fetcher = fetcher;
        this.param1 = p1;
        this.param2 = p2;
    }

    @Override
    public Data call() {
        return fetcher.fetchData(param1, param2);
    }
};

然后像这样使用它:

Future<Data> result1 = executorService.submit(new DataFetcherTask(fetcher, 1, 2));
Future<Data> result2 = executorService.submit(new DataFetcherTask(fetcher, 3, 4));

这里仍然没有可变状态的踪迹。