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.
Related
I have N tasks to execute, and the number of tasks is not fixed. The next task can only be executed after the previous task is completed. How can the entire task chain be executed asynchronously?
If the number of tasks is fixed, such as N=2, I can use the following code. How to do it if N is not fixed
public void futureTest() throws InterruptedException {
CompletableFuture<Integer> finalFuture = new CompletableFuture<>();
CompletableFuture<Integer> cf1 = doTask(1);
AtomicReference<CompletableFuture<Integer>> cf2 = new AtomicReference<>(new CompletableFuture<>());
cf1.whenComplete(((integer1, throwable1) -> {
if (throwable1 != null) {
finalFuture.completeExceptionally(throwable1);
return;
}
// when task1 complete then submit task2
cf2.set(doTask(2));
cf2.get().whenComplete(((integer2, throwable2) -> {
if (throwable2 != null) {
finalFuture.completeExceptionally(throwable2);
return;
}
finalFuture.complete(integer2);
}));
}));
finalFuture.whenComplete(((integer, throwable) -> {
System.out.println("all task is done");
}));
Thread.sleep(1000000);
}
private CompletableFuture<Integer> doTask(int index) {
CompletableFuture<Integer> cf = new CompletableFuture<>();
// Simulate task execution
THREAD_POOL.execute(() -> {
Thread.sleep(3_000);
cf.complete(index);
});
return cf;
}
I looked at Compeltable's API docs and none of them seem to solve my problem. I tried to use a loop to control the task submission, but all failed, unable to submit the next task after the previous task is completed
Refer to this answer on this thread Click here. Seems a duplicate of this question.
thenRun method is used to run the task after the previous future is completed successfully. This method will be skipped in case of any failures in previous stages.
whenComplete method is used as the final stage of execution chain. Here you will receive the composed result of all the other functions in the supply chain and you can choose to fail your future or handle exceptions accordingly inside this.
You can compose the futures for the individual tasks via CompletableFuture#thenCompose in a loop:
CompletableFuture<?> future = createFirstTask();
while (hasMoreTasks()) {
future = future.thenCompose(this::createNextTask);
}
Here every next tasks depends on the result of the previous one until no more task is left.
Conceptionally this is a fold operation, which unfortunately is not part of the API of CompletableFuture. But if you don't mind using my better future library (which is just a thin wrapper around CompleteableFuture), I just recently added support for folding streams of futures there.
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.
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.
I am looking for a way to execute batches of tasks in java. The idea is to have an ExecutorService based on a thread pool that will allow me to spread a set of Callable among different threads from a main thread. This class should provide a waitForCompletion method that will put the main thread to sleep until all tasks are executed. Then the main thread should be awaken, and it will perform some operations and resubmit a set of tasks.
This process will be repeated numerous times, so I would like to use ExecutorService.shutdown as this would require to create multiple instances of ExecutorService.
Currently I have implemented it in the following way using a AtomicInteger, and a Lock/Condition:
public class BatchThreadPoolExecutor extends ThreadPoolExecutor {
private final AtomicInteger mActiveCount;
private final Lock mLock;
private final Condition mCondition;
public <C extends Callable<V>, V> Map<C, Future<V>> submitBatch(Collection<C> batch){
...
for(C task : batch){
submit(task);
mActiveCount.incrementAndGet();
}
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
mLock.lock();
if (mActiveCount.decrementAndGet() == 0) {
mCondition.signalAll();
}
mLock.unlock();
}
public void awaitBatchCompletion() throws InterruptedException {
...
// Lock and wait until there is no active task
mLock.lock();
while (mActiveCount.get() > 0) {
try {
mCondition.await();
} catch (InterruptedException e) {
mLock.unlock();
throw e;
}
}
mLock.unlock();
}
}
Please not that I will not necessarily submit all the tasks from the batch at once, therefore CountDownLatch does not seem to be an option.
Is this a valid way to do it? Is there a more efficient/elegant way to implement that?
Thanks
I think the ExecutorService itself will be able to perform your requirements.
Call invokeAll([...]) and iterate over all of your Tasks. All Tasks are finished, if you can iterate through all Futures.
As the other answers point out, there doesn't seem to be any part of your use case that requires a custom ExecutorService.
It seems to me that all you need to do is submit a batch, wait for them all to finish while ignoring interrupts on the main thread, then submit another batch perhaps based on the results of the first batch. I believe this is just a matter of:
ExecutorService service = ...;
Collection<Future> futures = new HashSet<Future>();
for (Callable callable : tasks) {
Future future = service.submit(callable);
futures.add(future);
}
for(Future future : futures) {
try {
future.get();
} catch (InterruptedException e) {
// Figure out if the interruption means we should stop.
}
}
// Use the results of futures to figure out a new batch of tasks.
// Repeat the process with the same ExecutorService.
I agree with #ckuetbach that the default Java Executors should provide you with all of the functionality you need to execute a "batch" of jobs.
If I were you I would just submit a bunch of jobs, wait for them to finish with the ExecutorService.awaitTermination() and then just start up a new ExecutorService. Doing this to save on "thread creations" is premature optimization unless you are doing this 100s of times a second or something.
If you really are stuck on using the same ExecutorService for each of the batches then you can allocate a ThreadPoolExecutor yourself, and be in a loop looking at ThreadPoolExecutor.getActiveCount(). Something like:
BlockingQueue jobQueue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS,
0L, TimeUnit.MILLISECONDS, jobQueue);
// submit your batch of jobs ...
// need to wait a bit for the jobs to start
Thread.sleep(100);
while (executor.getActiveCount() > 0 && jobQueue.size() > 0) {
// to slow the spin
Thread.sleep(1000);
}
// continue on to submit the next batch