0

I am doing some experiments with the Java CompletableFuture. Here is the code

public class SpringBootAsyncApplication {

    public static void main(String[] args) {

        CompletableFuture.supplyAsync(() - > {

            return MailUtil.getMailInfo();

        }).thenAccept(content - > {
            System.out.println("Mail content: " + content);
        });
    }

}

class MailUtil {
    public static String getMailInfo() {
        return "Your email content";
    }

    public static boolean sendMail() {
        System.out.println("Send mail: completed");
        return true;
    }

    public static void logging() {
        System.out.println("Log: Send mail at " + System.currentTimeMillis());
    }
}

I run the program 3 times. All of them didn't return any output ? But when I replace return MailUtil.getMailInfo(); with number 5

CompletableFuture.supplyAsync(() - > {

    return 5;

}).thenAccept(content - > {
    System.out.println("Mail content: " + content);
});

then it runs as normal. Why is that ?

Bashir
  • 2,057
  • 5
  • 19
  • 44
kungho
  • 371
  • 1
  • 4
  • 16
  • I've run your code and it outputs "Mail content: Your email content". Edit. I've run the code multiple times and actually it sometimes it prints the output and sometimes it doesn't. – Amongalen Jun 17 '20 at 08:58
  • Thats strange. I am running on intelliji and it doesn't output the result Here is the link to the output : https://imgur.com/a/jTF6rzX – kungho Jun 17 '20 at 09:03
  • 4
    This is just a coincidence - the main thread exits before your async tasks are executed/completed. Add `.join()` at the end and you will always see the result. – Michał Krzywański Jun 17 '20 at 09:16
  • so by default completable future executes its task on DAEMON THREAD ? – kungho Jun 17 '20 at 09:25
  • @kungho from [javadocs](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html#supplyAsync-java.util.function.Supplier-): "task running in the ForkJoinPool.commonPool()" – Amongalen Jun 17 '20 at 09:28

1 Answers1

1

The result that you see is just a coincidence. The main thread exits before your async tasks are executed/completed. Add CompletableFuture::join at the end and you will always see the result :

CompletableFuture.supplyAsync(() - > {

    return MailUtil.getMailInfo();

}).thenAccept(content - > {
    System.out.println("Mail content: " + content);
}).join();

This is because when you use supplyAsync your task will be executed in one of the threads from ForkJoinPool.commonPool and by default threads from this pool are daemon threads so they do not stop JVM from exiting. You can verify this by checking the default thread factory associated with commonPool :

ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
ForkJoinWorkerThread forkJoinWorkerThread = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(forkJoinPool);

boolean daemon = forkJoinWorkerThread.isDaemon();
System.out.println(daemon);

And the output is true.

Michał Krzywański
  • 15,659
  • 4
  • 36
  • 63