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";
}
Community
  • 1
  • 1
user2727195
  • 7,122
  • 17
  • 70
  • 118

4 Answers4

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.

Holger
  • 285,553
  • 42
  • 434
  • 765
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.

VGR
  • 40,506
  • 4
  • 48
  • 63
  • 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. – user2727195 Feb 16 '17 at 22:00
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
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • 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 – user2727195 Feb 16 '17 at 19:25
  • @user2727195 Better then to use another thread then to run the joins and the subsequent callback – ControlAltDel Feb 16 '17 at 19:29
  • ok, you've a point. just to expand knowledge here, do you know CompletableFuture and does it apply to my question? – user2727195 Feb 16 '17 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 – ControlAltDel Feb 16 '17 at 19:41
  • lol no worries, but I'm open to other approaches, I'm not tied to this code in my question – user2727195 Feb 16 '17 at 19:48
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

bichito
  • 1,406
  • 2
  • 19
  • 23
  • 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 – ControlAltDel Feb 16 '17 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 Feb 16 '17 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 Feb 17 '17 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 Feb 17 '17 at 18:37