我有两个在其他线程上完成的ListenableFutures。每个未来都是不同的类型,我希望在它们完整时使用它们的两个结果。
使用番石榴是否有一种优雅的方式来处理这个问题?
答案 0 :(得分:9)
如果您想要某种类型的安全性,您可以执行以下操作:
class Composite {
public A a;
public B b;
}
public ListenableFuture<Composite> combine(ListenableFuture<A> futureA,
final ListenableFuture<B> futureB) {
return Futures.transform(futureA, new AsyncFunction<A, Composite>() {
public ListenableFuture<Composite> apply(final A a) throws Exception {
return Futures.transform(futureB, new Function<B, Compisite>() {
public Composite apply(B b) {
return new Composite(a, b);
}
}
}
}
}
ListenableFuture<A> futureA = ...
ListenableFuture<B> futureB = ...
ListenableFuture<Composite> result = combine(futureA, futureB);
在这种情况下,如果您愿意,Composite
可以是来自Apache Commons的Pair<A, B>
。
此外,未来任何一方的失败都会导致未来的合并失败。
另一个解决方案是查看Spotify团队的Trickle。 GitHub自述文件有一个示例,显示了类似问题的解决方案。
毫无疑问还有其他解决方案,但这是我脑海中浮现的问题。
答案 1 :(得分:3)
Runnable listener = new Runnable() {
private boolean jobDone = false;
@Override
public synchronized void run() {
if (jobDone || !(future1.isDone() && future2.isDone())) {
return;
}
jobDone = true;
// TODO do your job
}
};
future1.addListener(listener);
future2.addListener(listener);
不是很优雅,但应该做好。
或者,更优雅,但你需要演员:
ListenableFuture<List<Object>> composedFuture =
Futures.allAsList(future1, future2);
答案 2 :(得分:1)
自Guava v20.0起,您可以使用:
ListenableFuture<CombinedResult> resultFuture =
Futures.whenAllSucceed(future1, future2)
.call(callableThatCombinesAndReturnsCombinedResult, executor);
答案 3 :(得分:0)
如果您想要某种类型安全,可以使用姐妹Guava EventBus
包中的com.google.common.eventbus
来组合2个不同的独立任务的结果
为了举例,我们假设你们中的一个Futures
返回Integer
而另一个Double
。
首先,创建一个累加器(其他名称 builder , collector 等)类,您将使用EventBus注册为事件接收器。你可以看到它真的是一个POJO,它将会有Integer
和Double
个事件
class Accumulator
{
Integer intResult;
Double doubleResult;
@Subscribe // This annotation makes it an event handler
public void setIntResult ( final Integer val )
{
intResult = val;
}
@Subscribe
public void setDoubleResult ( final Double val )
{
doubleResult = val;
}
}
这个方法的实现将采用2个期货,并将它们组合成一个累加器。
final ListenableFuture< Integer > future1 = ...;
final ListenableFuture< Double > future2 = ...;
final ImmutableList< ListenableFuture< ? extends Object> > futures =
ImmutableList.< ListenableFuture<? extends Object> >of( future1, future2 );
final ListenableFuture< Accumulator > resultFuture =
Futures.transform(
// If you don't care about failures, use allAsList
Futures.successfulAsList( futures ),
new Function< List<Object>, Accumulator > ( )
{
@Override
public Accumulator apply ( final List< Object > input )
{
final Accumulator accumulator = new Accumulator( );
final EventBus eventBus = new EventBus( );
eventBus.register( accumulator );
for ( final Object cur: input )
{
// Failed results will be set to null
if ( cur != null )
{
eventBus.post( cur );
}
}
return accumulator;
}
}
);
final Accumulator accumulator = resultFuture.get( );
答案 4 :(得分:0)
这是一个简单的例子,可以添加2个可听的未来:
//Asynchronous call to get first value
final ListenableFuture<Integer> futureValue1 = ...;
//Take the result of futureValue1 and transform it into a function to get the second value
final AsyncFunction<Integer, Integer> getSecondValueAndSumFunction = new AsyncFunction<Integer, Integer>() {
@Override
public ListenableFuture<Integer> apply(final Integer value1) {
//Asynchronous call to get second value
final ListenableFuture<Integer> futureValue2 = ...;
//Return the sum of the values
final Function<Integer, Integer> addValuesFuture = new Function<Integer, Integer>() {
@Override
public Integer apply(Integer value2) {
Integer sum = value1 + value2;
return sum;
}
};
//Transform the second value so its value can be added to the first
final ListenableFuture<Integer> sumFuture = Futures.transform(futureValue2, addValuesFuture);
return sumFuture;
}
};
final ListenableFuture<Integer> valueOnePlusValueTwo = Futures.transform(futureValue1, getSecondValueAndSumFunction);