is it possible to run a completable future in the same thread in which it is created?

Viewed 1584

Would like to know if a completablefuture can be run in the thread in which it was created. You might ask why would I need to do so since completablefuture is for async programming. The reason is that I have few async tasks and some tasks that I want to run in the spawning thread so that I can use allOf etc and maintain consistency in the code

2 Answers

When you say you want to know whether "a completablefuture can be run in the thread in which it was created", you are exhibiting a wrong mindset. A CompletableFuture doesn't run. A CompletableFuture just encapsulates a value or exception, which can be set at most one time, which we call completing it.

The API offers a lot of methods for scheduling completion attempts, potentially asynchronous, but you shouldn't get distracted from the fact that you decide how to complete it.

There are simple alternatives to asynchronous completion:

CompletableFuture<String> f = CompletableFuture.completedFuture("hello");

creates an immediately completed future. Java 9 adds failedFuture to support creating an immediately exceptionally completed future.

You can also easily create a future to be completed at a later time within the same thread:

CompletableFuture<String> f = new CompletableFuture<>();

// arbitrary actions

f.complete("hello");

You can also use the factory methods with an executor, immediately running the action in the initiating thread:

CompletableFuture<String> f
  = CompletableFuture.supplyAsync(() -> "hello", Runnable::run);

or

CompletableFuture<String> f
  = CompletableFuture.supplyAsync(() -> {
    if(Math.random() > 0.5) throw new IllegalStateException();
    return "hello";
  }, Runnable::run);

to demonstrate the difference to an invocation of complete or creating an immediately completed future.

Of course, these possibilities can be combined with the other features, like allOf:

CompletableFuture<String> a = new CompletableFuture<>();
CompletableFuture<String> b = new CompletableFuture<>();
CompletableFuture<String> c = new CompletableFuture<>();

CompletableFuture.allOf(a, b, c).whenComplete((__, t) -> {
  if(t != null) System.err.println("failed with "+t);
  else System.out.println("all completed "+a.join()+", "+b.join()+", "+c.join());
});

System.out.println("step 1");
a.complete("foo");
System.out.println("step 2");
b.complete("bar");
System.out.println("step 3");
c.complete("baz");

Yes, perfectly possible. Here is a sample program which demonstrates

private static ExecutorService executor = Executors.newSingleThreadExecutor();

public static void main(String[] args)
{
    executor.execute(() -> {
        System.out.println("Scheduling " + Thread.currentThread().getName());
        CompletableFuture.supplyAsync(() -> {
            System.out.println("Sleeping " + Thread.currentThread().getName());
            try {
                Thread.sleep(2000);
            }
            catch (InterruptedException e) {}

            System.out.println("Returning " + Thread.currentThread().getName());
            return 123;
        },
        executor)
        .thenAccept(retValue -> System.out.println("Got value " + retValue + " " + Thread.currentThread().getName()));
    });
}

Output

Scheduling pool-1-thread-1
Sleeping pool-1-thread-1
Returning pool-1-thread-1
Got value 123 pool-1-thread-1
Related