Passing Class that runs task to Completable Future SupplyAsync - java

Trying to compare implementations of futures vs completed futures and check if the non blocking nature of completable futures is a better use case for my problem. Having an issue getting my completable impl to work correctly.
Collection<Future<ArrayList<MeterTariffValues>>> futures = new ArrayList<>();
List<CompletableFuture<GetSiteMeterTariffValues>> completableFutures = new ArrayList<>();
for (Site site : sites) {
completableFutures.add(
CompletableFuture.supplyAsync(new Supplier<GetSiteMeterTariffValues>() {
#Override
public GetSiteMeterTariffValues get() {
return new GetSiteMeterTariffValues(
site.getSite_id(),
methaneConversionVal,
nitrogenConversionVal,
bu_id,
region_id,
facility_id,
status,
resource_id,
metertype_id,
currentCalendarYear,
currentFiscalYear,
fiscalYearStartMonth,
dates,
meterMapper,
sqlSessionTemplate);
}
}, taskExecutor)
);
futures.add(
taskExecutor.submit(
new GetSiteMeterTariffValues(
site.getSite_id(),
methaneConversionVal,
nitrogenConversionVal,
bu_id,
region_id,
facility_id,
status,
resource_id,
metertype_id,
currentCalendarYear,
currentFiscalYear,
fiscalYearStartMonth,
dates,
meterMapper,
sqlSessionTemplate)));
}
The issue with the Completable implementation, is that it wont recognize that GetSiteMeterTariffValues returns a different type after the task is complete.
It returns
public ArrayList<MeterTariffValues> call()
But task executor is fine with this
for (Future<ArrayList<MeterTariffValues>> future : futures) {
long start = System.currentTimeMillis();
ArrayList<MeterTariffValues> siteMeterTariffMonthlyValues = future.get();
long end = System.currentTimeMillis();
long totalMS = end - start;
total += totalMS;
meterTariffValues.addAll(siteMeterTariffMonthlyValues);
}
So im wondering how i can do similar the above with completablefutures.
Note:GetSiteMeterTariffValues implements Callable<ArrayList>

CompletableFuture.supplyAsync() expects a Supplier which is the equivalent of Callable for ExecutorService.
The way you do it currently, you are just providing a Supplier that creates a Callable, but of course your Callable (GetSiteMeterTariffValues) is not called.
You just need to make GetSiteMeterTariffValues implement Supplier and use it directly in CompletableFuture.supplyAsync():
CompletableFuture.supplyAsync(
new GetSiteMeterTariffValues(
site.getSite_id(),
methaneConversionVal,
nitrogenConversionVal,
bu_id,
region_id,
facility_id,
status,
resource_id,
metertype_id,
currentCalendarYear,
currentFiscalYear,
fiscalYearStartMonth,
dates,
meterMapper,
sqlSessionTemplate),
taskExecutor)
Note that Supplier does not allow throwing checked exceptions, so you cannot just use a method reference to Callable.call().

Related

Best way to use Future in java

I have a set of jobs which I am submitting using executor framework and Future. Let's say that I have 100 futures. As of now, I am using Future.get and using the output for subsequent processing. However for further tuning, I want to change the flow as below:
iterate through the set of future tasks and start consuming the result as soon as a future task is complete. I am reading the API doc to understand what might be a good way to accomplish this but reaching out to see if there is a better way to accomplish what I am looking for.
Here is the sample code:
public class ImplCallable implements Callable<String> {
int timeOut;
ImplCallable(int timeOut) {
this.timeOut=timeOut;
}
public String call() throws Exception {
Thread.sleep(timeOut);
return Thread.currentThread().getName();
}
}
and the main class:
public class MainProg {
public static void main(String...args) throws Exception {
long startTimeInMillis = System.currentTimeMillis();
ImplCallable callable1 = new ImplCallable(1000);
ImplCallable callable2 = new ImplCallable(2000);
ExecutorService service = Executors.newFixedThreadPool(4);
Future<String> task1 = service.submit(callable1);
Future<String> task2 = service.submit(callable2);
List<Future<String>> futureList = new ArrayList();
futureList.add(task1);
futureList.add(task2);
String retVal;
for(Future<String> task:futureList) {
retVal = task.get();
//do something with the retVal
}
long endTimeInMillis = System.currentTimeMillis();
System.out.println("time taken by code - " + (endTimeInMillis-startTimeInMillis) + "-ms");
}
}
Basically I don't want to use Future.get() and wait for its completion. I want to know if either of the task is complete and use the result as soon as its done.
There are many ways do this so, without a concrete example, you won't get a concrete answer. Likely want to look at CompletableFuture which has many methods for defining follow-on work, combining work, splitting work etc.
Future<String> f = CompletableFuture.supplyAsync(() -> "INITIAL WORK")
.thenApply(String::toLowerCase) // Do some more work
.thenAccept(queue::add); // put results onto a queue something is reading from
f.join();
// Batch complete
I hope you are using Java 8 or later version.
Whenever you mention "as soon as a future task is complete", you want to use CompletableFuture and its .thenApply() method, as #drekbour suggests.
Then you have multiple threads running different tasks in non-determenistic sequence. But at the end you want to get all the results in the single (Main) thread. To achieve it, you can use CompletableFuture.allOf method, .join() it - and then iterate over all the (already completed) future results without waiting.

Get result of completablefuture

I am using completablefuture to be returned from an async thread in springboot application. My implementation is below. From my understanding a new thread should be started for each item in list and should process parallely. I understand .get will block the execution but as it is parallely running still i dont see any improvement in performance. Any suggestions on below please to improve the performance?
ServiceA.java
#Autowired
ServiceB serviceb;
public List<String> getNames(List<Item> items) {
List<CompletableFuture<String>> list = new ArrayList<>();
List<String> returnList = new ArrayList<>();
for( Item item: items) {
CompletableFuture<String> getItemName = serviceb.doProcess(item);
list.add(getItemName):
}
for( CompletableFuture name : list) {
returnList.add(name.get());
}
return returnList;
}
ServiceB.java
Class ServiceB {
#Async
Public CompletableFuture<String> doProcess(Item item)
{
//do process
}
You could call allOf to wait for all results. This will wait for all CompletableFuture to complete.
List<String> returnList = new ArrayList<>(items.size());
CompletableFuture<String>[] tasks = items.stream()
.map(value-> serviceb.doProcess(value).thenApply(returnList::add))
.toArray(CompletableFuture[]::new);
// wait for all tasks to finish
CompletableFuture.allOf(tasks).get(50, TimeUnit.SECONDS);
// return the results
return returnList;
Second solution would be to use an reactive approach like publisher/subscriber pattern (Spring WebFlux or JavaRx). This way your application would have little/no waiting operation. But this would affect your application architecture.
One Advice:
In order to create an CompletableFuture use the constructor with ExecutorService in order to keep in check number of threads and have control over running threads or when application shuts down.
You can use thenAccept to add the items to the list.
List<String> list = new CopyOnWriteArrayList<>();
CompletableFuture.allOf(
Stream.of(items).map(
i -> CompletableFuture.supplyAsync(i)
.thenAccept(list::add)
).toArray(CompletableFuture[]::new)
).get(10, SECONDS);
return list;
The get() will definitely not going to work out as it will block the main thread of execution to fetch the result from the async threads. A better option would be to use callback methods(thenApply() etc) accordingly so as to let the main thread continue its work.

Use ExecutorCompletionService to perform concurrent calls to different dependencies

I am trying to use the ExecutorCompletionService - https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorCompletionService.html, to try and perform concurrent calls to two different dependent packages.
The reason I am using ExecutorCompletionService is because I want to compare the results returned by both the dependencies and then emit a metric based on a specific requirement.
My code looks like this:
#Builder
#Slf4j
public class TestClass {
#NonNull private final ExecutorService threadPool = Executors.newFixedThreadPool(2);
#NonNull private final ExecutorCompletionService<ResultStructure1> dependency1Thread = new ExecutorCompletionService<>(threadPool);
#NonNull private final ExecutorCompletionService<ResultStructure2> dependency2Thread = new ExecutorCompletionService<>(threadPool);
public void myMethod() {
RequestObject1 firstDependencyRequest = RequestObject1.builder()
.attribute1("someValue")
.attribute2("secondValue");
RequestObject2 secondDepdencyRequest = RequestObject1.builder()
.attribute1("depdency2Value")
.attribute2("depdency2Secondvalue");
dependency1Thread.submit(() -> dependency1Client1.call(firstDependencyRequest));
dependency2Thread.submit(() -> dependencyClient2.call(secondDepdencyRequest));
final Future<ResultStructure1> future1 = dependency1Thread.take();
final Future<ResultStructure2> future2 = dependency2Thread.take();
try {
ResultStructure1 = future1.get();
ResultStructure2 = future2.get();
} catch (ExecutionException e) {
log.error("Exception calling dependency", e);
throw e;
}
}
}
Is this the correct way to be using ExecutorCompletionService for different dependencies? Is there a way to have a single executorService and have both the dependencies be called from that?
Is this the correct way to be using ExecutorCompletionService for
different dependencies?
Unfortunately, no. You'd typically use it to execute tasks returning similar type of results while you wait for their execution and their results to be available. Internally it uses a BlockingQueue where it adds the Futures as the tasks complete, which is then returned by its blocking take method.
So, if you do want to use an ExecutorCompletionService, you'd have to come up with a base/common type for ResultStructure1 and ResultStructure2 (i.e., ResultStructure), and declare a completion service like below -
private final ExecutorCompletionService<ResultStructure> completionService =
new ExecutorCompletionService<>(threadPool)
and then -
completionService.submit(() -> dependency1Client1.call(firstDependencyRequest));
completionService.submit(() -> dependencyClient2.call(secondDepdencyRequest));
You can then wait for their results to be available using the blocking take method -
Future<ResultStructure> result1 = completionService.take();
Future<ResultStructure> result2 = completionService.take();
Please note that at this point, we have no way of finding out which Future represents which concrete result type. So you have no way of comparing the results.
My recommendation would be to simply use ExecutorService directly.

ThreadPoolExecutor, Futures: correlating requests and responses

I'm trying to use a ThreadPoolExecutor along with Future (results) and Callable (task to be executed), but I can't figure out a simple way of correlating input (Callable) with the corresponding result (Future), it seems the only sensible way would be to create a wrapper (example) that contains all items, but this might be too much overhead for such a simple task.
Am I wrong? Any suggested alternatives?
A better approach would be to use the invokeAll() method instead of submit(). You need to provide a collection of Callables to it and it will return a collection of Futures in the same sequential order as your tasks. Moreover, invokeAll() lets you define a timeout, so you don't need latches. It will be something like that:
List<Callable> jobs = new ArrayList<>(requests.size());
for (String request : requests) {
jobs.add(new MyCallable(request));
}
List<Future<ProcessedResponse>> futures = executor.invokeAll(jobs, timeout, TimeUnit.MILLISECONDS);
Iterator<String> it = requests.iterator();
for (Future<ProcessedResponse> future: futures) {
String request = it.next(); // This request corresponds to this future
if (future.isDone()) {
results.add(new Result(request, future.get()));
} else {
future.cancel(true);
}
}

Java Concurrency: How can I tell which Future belongs to which Callable during processing?

I have a collection of Callables and a ExecutorService. When I invokeAll, I get back a list of Future objects. How can I tell which Future object mapped to which Callable before the Future completes? I can tell afterwards because the
Code:
ExecutorService es = .....;
Collection<Callables> uniqueCallables = .....; // each Callable is unique!
List<Future> futures = es.invokeAll(uniqueCallables);
// TODO--find unique Future A which is the future for Callable A!
Based on Java reference, invokeAll(uniqueCallables) preserves the order in List<Future> as the order produced by uniqueCallables.iterator():
Returns:
A list of Futures representing the tasks, in the same
sequential order as produced by the iterator for the given task list,
each of which has completed.
Sounds like you simply need to be able to lookup the original callable from a Future. If you weren't using invokeAll, you could decorate the Executor wrapping the submit() to create a ContextualFuture that keeps a reference to the original callable.
/*pseudo example*/
class ContextualFuture<RETURN> implements Future<RETURN> {
private Callable<RETURN> callable;
private Future<RETURN> wrappedFuture;
public ContextualFuture(Callable<RETURN> callable, Future<RETURN> future){
this.callable = callable;
this.future = future;
}
// implemented/wrapped methods
}
class ContextualThreadPool {
private ExecutorService wrappedExecutor;
public <T> ContextualFuture<T> submit(Callable<T> task){
Future<T> f = wrappedExecutor.submit(task);
return new ContextualFuture<T>(task, f);
}
}

Categories

Resources