他のスレッドで完了する2つのListenableFutureがあります。それぞれの未来は異なるタイプであり、両方が完成したときに両方の結果を使用したいと思います。
Guavaを使用してこれを処理するエレガントな方法はありますか?
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);
Guava v20.0以降、次を使用できます:
ListenableFuture<CombinedResult> resultFuture =
Futures.whenAllSucceed(future1, future2)
.call(callableThatCombinesAndReturnsCombinedResult, executor);
ここでJavaドキュメントの例を見てください
以下は、2 つのリッスン可能な Future の追加を実行する簡単な例です。
//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);
型の安全性が必要な場合はEventBus
、姉妹の Guavacom.google.common.eventbus
パッケージを使用して、2 つの異なる独立したタスクの結果を組み合わせることができます。
例として、あなたの 1 人がFutures
戻っInteger
てきて、もう1 人がDouble
.
まず、EventBus でイベント シンクとして登録するアキュムレータ (別名builder、collectorなど) クラスを作成します。Integer
ご覧のとおり、これは実際にはDouble
イベントを処理する POJO です。
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( );