0

Edit: My question is different, it has no relevance to the linked question.

I've following code with completion handler.

FutureTask<Void> futureTask = new FutureTask<Void>(() -> {
    System.out.println("callback");
    return null;
});

Runnable task = () -> {
    for(int i=0; i<5; i++) {
        System.out.println(Thread.currentThread().getName() + " " + i);
    }
    futureTask.run();
};

new Thread(task).start();
new Thread(task).start();

Basically I'm looking for completion handler for variable number of tasks, or is there another approach?

I'm inspired from this answer but seems it's part of some library while I'm looking for a native solution.

Completable Future???

Here's my attempt with completable futures with the result handler at the end.

public void test() {
    CompletableFuture
            .supplyAsync(() -> method1())
            .supplyAsync(() -> method2())
            .supplyAsync(() -> result());
}

public String method1() {
    System.out.println("calling 1");
    return "method1";
}

public String method2() {
    System.out.println("calling 2");
    return "method2";
}

public String result() {
    System.out.println("result");
    return "result";
}
4
  • Why can't futureTask.run(); be replaced with in old method? Commented Feb 16, 2017 at 19:36
  • You could basically chain your tasks by implementing one that invokes Thread.join() on its predecessor(s) and then does whatever you want.
    – Izruo
    Commented Feb 16, 2017 at 19:41
  • Possible duplicate of wait until all threads finish their work in java Commented Feb 17, 2017 at 13:33
  • @Ravindrababu not a duplicate. Commented Feb 17, 2017 at 16:33

4 Answers 4

3

Assuming that your method result() returns a value that you want to retrieve, i.e. is declared like Type result(), you can use

CompletableFuture<Type> f = CompletableFuture.allOf(
    CompletableFuture.runAsync(() -> method1()),
    CompletableFuture.runAsync(() -> method2())
).thenApply(_void -> result());

Each runAsync creates an individual asynchronous CompletableFuture that will be completed once the Runnable has been executed. It’s the same as supplyAsync, except that it doesn’t return a result.

allOf create a CompletableFuture that will be completed, once all specified futures are completed, hence, any chained dependent action will only run after all futures have been completed. By using thenApply we create a dependent future that will be completed with the return value of result().

If result() is not intended to return a value, but just an action that should run after all other actions have been completed, you can use

CompletableFuture.allOf(
    CompletableFuture.runAsync(() -> method1()),
    CompletableFuture.runAsync(() -> method2())
).thenRun(() -> result());

instead.

1

One easy approach is to submit your Runnable(s) to an ExecutorService, then call shutdown, then call awaitTermination:

ExecutorService executor = Executors.newWorkStealingPool();
executor.submit(task);
executor.submit(task);

executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

No need to use CompletableFuture.

1
  • can you please make it a different caller and different responder, the executioner will be a different method and callback with result will be in a different one. Commented Feb 16, 2017 at 22:00
0

Depending on how much control you want you could use a ThreadPoolExecutor:

tpe.execute(Runnable);

Wait for the active count == 0;

then shutdown the executor.

Or keep the threads in a structure.

Wait for an specific TTL then interrupt them if the state is RUNNABLE

4
  • right. It seems like isTerminated() might be the method to wait for with this. I was going to add this to my answer, but thought it would overly complicate things Commented Feb 16, 2017 at 19:27
  • It just depends on how one wants to deal with them. I tend to avoid pools because I rather keep the capacity of pulling the plug when I want to
    – bichito
    Commented Feb 16, 2017 at 19:29
  • If you have a ThreadPoolExecutor, just use invokeAll to submit a list of tasks and wait for their completion. No need to use kludges like active count or shutdown.
    – Holger
    Commented Feb 17, 2017 at 17:25
  • If you have a list but if you don't, like building the runnables on the fly, this is what you do. No kludges. But if one of the runnables never gives up control your idea is stuck. that's why I use pools sparsely. Or have a TTL with an active count
    – bichito
    Commented Feb 17, 2017 at 18:37
0

Save the links to the threads you've created, and call join()

Thread a = new Thread(task);
Thread b = new Thread(task);
a.start();
b.start();

a.join();
b.join();
//guaranteed that both threads have completed here
5
  • It's going to block just there, I want to call these threads and forget about it, method returns, and I expect followup in the callback. thanks for teaching me join though Commented Feb 16, 2017 at 19:25
  • @user2727195 Better then to use another thread then to run the joins and the subsequent callback Commented Feb 16, 2017 at 19:29
  • ok, you've a point. just to expand knowledge here, do you know CompletableFuture and does it apply to my question? Commented Feb 16, 2017 at 19:31
  • @user2727195 But there's really no Future here... You're not looking for a result, just wanting to wait to start the next step after both threads have completed. So no, it does not apply here... Put another way "YOU HAVE NO FUTURE KID!" yuk yuk yuk yuk yuk... Okay, I've had my moment Commented Feb 16, 2017 at 19:41
  • lol no worries, but I'm open to other approaches, I'm not tied to this code in my question Commented Feb 16, 2017 at 19:48

Not the answer you're looking for? Browse other questions tagged or ask your own question.