Скажем, у меня есть две тяжелые операции блокировки ввода-вывода, findMatchInSomeDB () и getDetailsFromOtherDB (String objectKey). Кроме того, я хочу, чтобы они работали в фоновом режиме и использовали Guava Futures, чтобы связать их вместе, потому что один зависит от результата другого (я знаю, что это можно было бы просто сделать последовательно в простом Callable, но сделать его простым для иллюстративные цели) :
Есть ли практическая или нюансированная разница между consumeChain
и consumeChainAsync
методами ниже?
import com.google.common.base.Function;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
public class Consumer
{
private final Retriever retriever;
private final ListeningExecutorService executorSvc;
public Consumer(Retriever retriever, ListeningExecutorService executorSvc)
{
this.retriever = retriever;
this.executorSvc = executorSvc;
}
private void consumeChain(String searchCriteria) throws Exception
{
ListenableFuture<String> futureMatch = executorSvc.submit(
() -> retriever.findMatchInSomeDB(searchCriteria));
Function<String, DataObject> keyToDataObj = objectKey ->
retriever.getDetailsFromOtherDB(objectKey);
// using "real" executor service so transform function runs
// in the background
ListenableFuture<DataObject> futureDataObj = Futures.transform(
futureMatch, keyToDataObj, executorSvc);
// ...do some other stuff in this thread...
// do something with futureDataObj result
futureDataObj.get();
}
private void consumeChainAsync(String searchCriteria) throws Exception
{
ListenableFuture<String> futureMatch = executorSvc.submit(
() -> retriever.findMatchInSomeDB(searchCriteria));
AsyncFunction<String, DataObject> keyToDataObj = objectKey ->
{
return executorSvc.submit(
() -> retriever.getDetailsFromOtherDB(objectKey));
};
// using DirectExecutor because the transform function
// only creates and submits a Callable
ListenableFuture<DataObject> futureDataObj = Futures.transformAsync(
futureMatch, keyToDataObj, MoreExecutors.directExecutor());
// ...do some other stuff in this thread...
// do something with futureDataObj
futureDataObj.get();
}
}
Насколько я могу судить, обе будут выполнять каждую тяжеловесную операцию через executorSvc
, и обе будут распространять отмену и / или сбой выполнения.
Кажется, что единственная точка transformAsync
(вместо простого использования transform
с исполнителем, отличным от DirectExecutor) - это когда вы работаете с API, который возвращает ListenableFuture вместо непосредственного выполнения операции. Я что-то упустил?