3

I am making critical use of:

 CompletableFuture
  .delayedExecutor(1, TimeUnit.MILLISECONDS).execute(() -> {});

From what I have read online, it's common for this to use a new thread for every call. I am wondering if there is a way to re-use a thread instead of creating new threads?

Update:

I wasn't clear - I want to use CompletableFuture, but I want CompletableFuture to reuse a certain thread, instead of managing its own threads.

I see this question: CompletableFuture reuse thread from pool

but it recommends using an environment variable - I am wondering if there is a way to do this programmatically.

5
  • How many processors do you have?
    – shmosel
    Commented Feb 7, 2019 at 1:58
  • 2
    Why aren't you using an ExecutorService to dispatch that? Commented Feb 7, 2019 at 2:05
  • I can use ExecutorService to dispatch, but I didn't know I could do that, can you add an answer showing how? Commented Feb 7, 2019 at 2:34
  • @shmosel 8 processors .. this code is going to run on many different machines not just my laptop at home or whatever Commented Feb 7, 2019 at 4:09
  • Then it should use a thread pool out of the box.
    – shmosel
    Commented Feb 7, 2019 at 4:15

2 Answers 2

2

Executor new Thread is created for every set of tasks

An Executor is normally used instead of explicitly creating threads. For example, rather than invoking new Thread(new(RunnableTask())).start() for each of a set of tasks, you might use: for each of a set of tasks

Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());

So if you want to reuse the threads, create a thread pool by using ExecutorService or ThreadPoolExecutor, so one of the threads from the pool will execute the runnable tasks.

If all the threads are busy, tasks will be queued up to a certain limit and after that will get rejected through a RejectedExecutionException.

Example

public class NewMain { 

    private static final ExecutorService ex = Executors.newFixedThreadPool(3);

    public static void main(String[] args) {
        Runnable r = () -> System.out.println(Thread.currentThread().getName());
        ex.execute(r);

        CompletableFuture<Void> c = CompletableFuture.runAsync(r, ex);
    }
}

Jdk-8 Use CompletableFuture.runAsync and pass runnable, Executor

public static CompletableFuture runAsync(Supplier supplier, Executor executor)

Returns a new CompletableFuture that is asynchronously completed by a task running in the given executor after it runs the given action.

2
  • Hmmm but how does this integrate with CompletableFuture? TMK, CompletableFuture uses its own threads, sometimes many threads. My goal was to tell CompletableFuture to use threads from a specific pool, so I am not sure if this answers my question. Commented Feb 7, 2019 at 3:43
  • I updated the OP to make the question a little clearer, let me know if it is or not Commented Feb 7, 2019 at 3:44
1

From what I have read online, it's common for this to use a new thread for every call.

(1) It's the case only if the machine doesn't support parallelism or you made it to not support it by setting the system property java.util.concurrent.ForkJoinPool.common.parallelism to 0 or 1.

8 processors

(2) If the machine does support parallelism, ForkJoinPool.commonPool() is used and the parallelism level is set, I guess, to the number of available processors (which can be determined by Runtime#availableProcessors).

In a scenario with 8 processors, 7-8 threads will probably be created to serve the common ForkJoinPool.

I want to use CompletableFuture, but I want CompletableFuture to reuse a certain thread, instead of managing its own threads.

A DelayedExecutor just submits tasks to the underlying Executor, which is either a ThreadPerTaskExecutor (1) or a ForkJoinPool (2).

Fortunately, you can manually specify an Executor which will be employed by the DelayedExecutor to delegate tasks to.

Executor delayedExecutor = 
     CompletableFuture.delayedExecutor(1, TimeUnit.MILLISECONDS, executor);

It gets us back to your previous question, where I pointed out that an Executor can be defined with a ThreadFactory.

Executor executor = Executors.newCachedThreadPool(YourThreadClass::new);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.