我已经编写了一些代码,这些代码基本上负责通过我向客户提供的库方法按顺序编排一些API,称为" orchestrate" (是的,我知道这么原始)。这个orchestrate方法背后的内容只不过是按照接收顺序执行API的循环,而后者又被委托给许多类,这些类包含用于构建请求,调用API的一些业务逻辑,对响应执行一些验证并最终返回api结果。因此,如果客户端在apis:
{a1, a2, a3, a4, a5}
列表中发送,它将以完全阻塞的方式按顺序执行每个api。
我试图加强这一点,以便我可以并行调用多个API,具体取决于我如何从客户端接收指令。可以把它想象成客户端向我发送一个列表,例如:{ {a1, a2}, {a3}, {a4, a5} }
这意味着我想并行执行a1和a2(这意味着构建他们的请求,调用apis,验证响应)。然后等到我确定他们两个都完成了。然后执行a3,等到我确定已完成。最后,我想执行a4和a5并遵循通常的模式。
现在,我很想将期货用于他们提供的简单抽象,以便使用.get()
方法执行等待响应的方法。但是我注意到下面的executorService需要的是未来对call()
方法的调用。这很好,但让我觉得每个类实现的call()
方法可能需要访问" local"数据是为了完成它的工作(毕竟,我不能通过call()方法传递任何特定的参数)。我真的想避免持有任何局部可变状态,因为这带来了自己的副作用。
有没有办法让我不能保持本地状态并仍然使用期货来处理我的多线程用例?或者我对期货的理解是完全错误的,我错过了一些明显的东西?如果没有,是否有任何建议可以通过一些替代方案向前推进?
答案 0 :(得分:1)
好的,所以你有一个类以阻塞的方式从网页获取一些数据,并采用一些参数:
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);
我在这里看不到任何可变状态。
为避免重复代码和使用匿名类,您可以定义顶级类:
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));
这里仍然没有可变状态的痕迹。