Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CompletableFuture runAsync vs new Thread

Context: I've read this SO thread discussing the differences between CompletableFuture and Thread.

But I'm trying to understand when should I use new Thread() instead of runAsync().

I understand that runAsyn() is more efficient for short/one-time parallel task because my program might avoid the overhead of creating a brand new thread, but should I also consider it for long running operations?

What are the factors that I should be aware before considering to use one over the other?

Thanks everyone.

like image 241
Some_user_qwerty Avatar asked Jul 03 '18 12:07

Some_user_qwerty


2 Answers

The difference between using the low-level concurrency APIs (such as Thread) and others is not just about the kind of work that you want to get done, it's also about the programming model and also how easy they make it to configure the environment in which the task runs.

In general, it is advisable to use higher-level APIs, such as CompletableFuture instead of directly using Threads.

I understand that runAsyn() is more efficient for short/one-time parallel task

Well, maybe, assuming you call runAsync, counting on it to use the fork-join pool. The runAsync method is overloaded with a method that allows one to specify the java.util.concurrent.Executor with which the asynchronous task is executed.

Using an ExecutorService for more control over the thread pool and using CompletableFuture.runAsync or CompletableFuture.supplyAsync with a specified executor service (or not) are both generally preferred to creating and running a Thread object directly.

There's nothing particularly for or against using the CompletableFuture API for long-running tasks. But the choice one makes to use Threads has other implications as well, among which:

  • The CompletableFuture gives a better API for programming reactively, without forcing us to write explicit synchronization code. (we don't get this when using threads directly)
  • The Future interface (which is implemented by CompletableFuture) gives other additional, obvious advantages.

So, in short: you can (and probably should, if the alternative being considered is the Thread API) use the CompletableFuture API for your long-running tasks. To better control thread pools, you can combine it with executor services.

like image 133
ernest_k Avatar answered Sep 19 '22 17:09

ernest_k


The main difference is CompletableFuture run your task by default on the ForkJoinPool.commonPool. But if you create your own thread and start it will execute as a single thread, not on a Thread pool. Also if you want to execute some task in a sequence but asynchronously. Then you can do like below.

    CompletableFuture.runAsync(() -> {
        System.out.println("On first task");
        System.out.println("Thread : " + Thread.currentThread());
    }).thenRun(() -> {
        System.out.println("On second task");
    });

Output:

On first task
Thread : Thread[ForkJoinPool.commonPool-worker-1,5,main]
On second task

If you run the above code you can see that which pool CompletableFuture is using.

Note: Threads is Daemon in ForkJoinPool.commonPool.

like image 36
Amit Bera Avatar answered Sep 20 '22 17:09

Amit Bera