问题
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.
回答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 wantCompletableFutureto 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);
回答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.
来源:https://stackoverflow.com/questions/54564805/force-re-use-of-thread-by-completablefuture