Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use CompletableFuture on ForkJoinpool and avoid thread waiting

Hello I thought with CompletableFuture and the default ForkJoinPool I could optimize execution of task more than a classic ExecutorService but I missing something

With this code the execution takes 1 seconds, I have 3 worker threads:

for (int i = 0; i < 3; i++) {
    final int counter = i;
    listTasks.add(CompletableFuture.supplyAsync(() -> {
        Thread.sleep(1000);
        System.out.println("Looking up " + counter + " on thread " + Thread.currentThread().getName());
        return null;
    }));
}

OK, seems normal.

But with this code, it takes 3 seconds:

for (int i = 0; i < 9; i++) {
    final int counter = i;
    listTasks.add(CompletableFuture.supplyAsync(() -> {
        Thread.sleep(1000);
        System.out.println("Looking up " + counter + " on thread " + Thread.currentThread().getName());
        return null;
    }));
}

I thought that sleeping thread would be used to launch other waiting task, it should takes also 1 seconds. I've read for example that IO WAINTING thread state would mean that thread can be reused for other task. Can I test this behaviour with Thread.sleep()? Does my test method is wrong or did I understand something wrongly?

like image 334
bodtx Avatar asked Aug 26 '16 15:08

bodtx


People also ask

Does CompletableFuture use ForkJoinPool?

Yes! CompletableFuture executes these tasks in a thread obtained from the global ForkJoinPool. commonPool(). But hey, you can also create a Thread Pool and pass it to runAsync() and supplyAsync() methods to let them execute their tasks in a thread obtained from your thread pool.

Is CompletableFuture thread safe?

CompletableFuture is inherently thread-safe The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation.

How many threads does ForkJoinPool use?

Implementation notes: This implementation restricts the maximum number of running threads to 32767. Attempts to create pools with greater than the maximum number result in IllegalArgumentException .

Is CompletableFuture asynchronous?

What is CompletableFuture? A CompltableFuture is used for asynchronous programming. Asynchronous programming means writing non-blocking code. It runs a task on a separate thread than the main application thread and notifies the main thread about its progress, completion or failure.


2 Answers

A sleeping thread cannot be used to do the job of another thread (especially, one thread cannot sleep for another thread). It's only CPU that can switch to the second thread when the first one goes to sleep.

When you provide a task to CompletableFuture.supplyAsync(), it goes to the default instance of ForkJoinPool that has as many threads as your computer has CPUs. You manually set allocated three threads to your default ForkJoinPool, so your nine tasks are distributed equally between them: each thread executes three tasks consecutively. So, you have three seconds as the result.

like image 93
Andrew Lygin Avatar answered Nov 15 '22 02:11

Andrew Lygin


Let's do the math. If you have 9 tasks and each task sleeps for 1 second and you have 2 processors you can only run 2 1-second sleeps at a time. Run this with 9 tasks and you get at least 3 seconds elapsed or at most most 4 seconds elapsed.

This isn't the same as non-blocking IO because this Runnable thread is CPU bound and will not give up the CPU until it completes (despite the sleep). If you look at things like RxJava's IO thread pool it creates one thread per task which is acceptable for IO tasks (but not CPU bound tasks).

like image 42
John Vint Avatar answered Nov 15 '22 02:11

John Vint