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);
}
}
Related
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.
Consider the following Java code (a simplified version of what I am working with - if there are errors it's because I haven't run it through a compiler):
CountdownLatch latch = new CountdownLatch(collection.size());
for(Whatever thing : collection){
provider.doWork(thing, result -> {
process(result);
latch.countDown();
};
}
try {
latch.await();
} catch (InterruptedException ignore) {}
doMoreWork();
So I run a number of asynchronous tasks, and wait for them all to be done before proceeding. Right now I'm accumulating the result of the asynchronous tasks in a list. This works and it's fine, but I'm looking at whether there's a cleaner implementation using Futures or something similar. The issue is the asynchronous call. A Callable is supposed to return the result of its work, but the result of this work won't be known until later. It's not worth rewriting doWork to be synchronous. Should I just leave this alone, or is there an option out there? Partly my interest is in better code but partly in just learning more about concurrency options. If it matters, this is in an Android app.
This is an approach using ExecutorService and Future, didn't tested on android but all available on level 1 api:
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Future<String>> pending = new ArrayList<Future<String>>();
for(Whatever thing : collection) {
Future<String> future = executor.submit(new Callable<String>() {
public String call() throws Exception {
return doWork();
}
});
pending.add(future);
}
for (Future<String> result : pending) {
System.out.println("Your result ASAP:" + result.get());
}
executor.shutdown();
It will return as soon as the current item is done, in the order the were submitted.
void process(String question){
Callable<ResponseList> callable1 = () -> this.stsCompute question);
Future<ResponseList>task1 = executorService.submit(callable1);
Callable<ResponseList> callable2 = () -> this.dssmCompute(question);
Future<ResponseList>task2 = executorService.submit(callable2);
try{
ResponseList stsResponse = task1.get();
ResponseList dssmResponse = task2.get();
}catch (Exception e){
e.printStackTrace();
}
// Do I need to wait until the first 2 threads complete?
processResponse(stsResponse, dssmResponse);
}
In this "process" method, I have two additional threads 'callable1' & 'callable2' to concurrently execute. I want to make sure only when these two tasks complete, the method in the main thread 'processResponse()' can start to be executed.
In such a case, do I need to add any additional control to ensure the order of the execution, is it already good enough? If not, how to make that control happen?
You should use ExecutorService.invokeAll which will return List of Futures when complete. Besides I would use a shorter syntax, something like
List<Future> futures = executorService.invokeAll(Arrays.asList(()->dssmCompute(), ()->dssmCompute()));
With Java8+ i would suggest use Completable Futures. It supports exactly the use case you are trying to achieve.
Completable Futures: Java 8
Sample Algorithm looks like:
var cf = CompletableFuture.supplyAsync(() -> processQuestion()).runAsync(() -> processResponse)
Note: var is typeInference supports in java 10+
Also, there are plenty of Examples on Completable Futures
here is two options , just bit confuse which one is best to go.
Option 1:
ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
.map(task -> CompletableFuture.runAsync(task, es))
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();
es.shutdown();
Option 2:
ExecutorService es = Executors.newFixedThreadPool(4);
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
futures.add(es.submit(task));
}
for(Future<?> future : futures) {
try {
future.get();
}catch(Exception e){
// do logging and nothing else
}
}
es.shutdown();
Here putting future.get(); in try catch is good idea right?
Since you effectively hold each submitted Future in a list of of futures by doing this:
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
futures.add(es.submit(task));
}
You can very easily check if all the submitted jobs are done executing just, by invoking the Future#isDone method, which wilkl return true or false based on whether the task has finished or not. You can check more on this on the related documentation here.
Hence, with the above in mind you could very well create a simple helper method, that will iterate the list of your futures and check on their state. For example:
private boolean areJobsDone() {
return futures.stream()
.allMatch(Future::isDone);
}
Note that in contrast to the Future#get method, isDone is non blocking (as it's not waiting for the task to return it's result) as it effectively queries it's state.
With this you can go ahead and check for the state of your runnables, blocking the flow with a loop that will invoke the helper method, before proceeding.
Hope this helps.
There is another way to wait for all tasks to complete. After you submitted all of your tasks, call
es.shutdown()
es.awaitTermination(Long.MAX_VALUE, TimeUnit.NANO_SECONDS)
Oracle's Java Docs read:
shutdown [...] Initiates an orderly shutdown in which previously submitted tasks are executed.
awaitTermination [...] Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
Concerning the timeout: with the above values, the thread-pool will only terminate after about 300 years.
Similar to the Aris_Kortex' proposal,
List<CompletableFuture<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
futures.add(CompletableFuture.runAsync(task, es));
}
and then create the combined CompletableFuture:
CompletableFuture<Void> cf = CompletableFuture.allOf(futures.toArray(futires.size()));
then you can wait for all tasks synchronously:
cf.get();
synchronously with timeout:
cf.get(1, TimeUnit.SECOND);
of asynchronously:
cf.thenRun(()->{finalActions();});
I'v got ConcurrentLinkedDeque which I'm using for synchronic push/pop elements,
and I'v got some async tasks which are taking one element from stack and if this element has neighbors It's pushing it to stack.
Example code:
private ConcurrentLinkedDeque<Item> stack = new ConcurrentLinkedDeque<>();
private ExecutorService exec = Executors.newFixedThreadPool(5);
while ((item = stack.pollFirst()) != null) {
if (item == null) {
} else {
Runnable worker = new Solider(this, item);
exec.execute(worker);
}
}
class Solider{
public void run(){
if(item.hasNeighbors){
for(Item item:item.neighbors){
stack.push(item)
}
}
}
}
I would like to have additional statement in while loop which answers the question - "any task in Executor is working?"
There isn't a clean way to check if all Runnables are done if you use ExecutorService.execute(Runnable). Unless you build a mechanism to do so in the Runnable itself (which is sloppy in my opinion).
Instead:
Use ExecutorService.submit(Runnable). This method will return a Future<?> which is a handle to the result of a Runnable. Using Futures provides a clean way to check results.
All you have to do is maintain a list of Futures that you submit, and then you can iterate over the whole list of Futures and either:
A) wait for all the futures to be done in a blocking way or
B) check if all the futures are done in a non-blocking way.
Here is a code example:
List<Future<?>> futures = new ArrayList<Future<?>>();
ExecutorService exec = Executors.newFixedThreadPool(5);
// Instead of using exec.execute() use exec.submit()
// because it returns a monitorable future
while((item = stack.pollFirst()) != null){
Runnable worker = new Solider(this, item);
Future<?> f = exec.submit(worker);
futures.add(f);
}
// A) Await all runnables to be done (blocking)
for(Future<?> future : futures)
future.get(); // get will block until the future is done
// B) Check if all runnables are done (non-blocking)
boolean allDone = true;
for(Future<?> future : futures){
allDone &= future.isDone(); // check if future is done
}
Update: with Java 8+ CompletableFutures you can manage this with its new callback functions. First you will need to create all of the CompletableFutures you need which will also start running, eg:
We need to accumulate all the futures generated in an Array in order to pass them later to CompletableFuture.allOf(CompletableFutures...)
So let's say you have a list of people you want to calculate its days until birthday asynchronously:
First we create all those needed futures and collect them together in an array:
CompletableFuture<?>[] completables = people.stream()
.map(p -> createCompletableFuture(p))
.toArray(CompletableFuture<?>[]::new);
private CompletableFuture createCompletableFuture(Person p) {
return CompletableFuture.runAsync(daysUntillBirthday(p));
}
Then you pass those completables to a new CompletableFuture:
CompletableFuture c = CompletableFuture.allOf(completables)
And you can now check if there are still futures running with:
c.isDone()
This may not be the cleanest solution, but you can use ThreadPoolExecutor.getActiveCount() to check how many threads are actively executing tasks.
Implementing this within a while loop with a simple condition to check if the active thread count is zero is a palatable solution.
Here is a code example:
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
for (int x = 0; x < 4; x++) {
Runnable worker = new Solider(this,item);
executor.execute(worker);
}
// Now check for active threads.
while(executor.getActiveCount()!=0)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
executor.shutdown();
The while block directly answers your question.
IE - If the while block is active, tasks are being executed.