Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ThreadPoolExecutor: how does it reuse threads

I read that ThreadPoolExecutor has pool of threads and this pool is destined to reduce cost of creation new threads (at least I understood phrase below in such way):

When you send a task to the executor, it tries to use a pooled thread for the execution of this task, to avoid continious spawning of threads. [Java 7 Concurrency Cookbook]

BUT, as I know we have got no way to restart thread in Java.

Question: How does ThreadPoolExecutor avoid creation of new threads?

like image 318
VB_ Avatar asked Mar 01 '14 09:03

VB_


People also ask

Does Python ThreadPoolExecutor reuse threads?

Heterogeneous tasks, not homogeneous tasks. Reuse threads, not single use. Manage multiple tasks, not single tasks.

How do you reuse threads?

One way to do your own thread pool is to use a blocking queue on to which you enqueue runnables and have each of your thread, once it's done processing the run() method of a Runnable , dequeue the next Runnable (or block) and run its run() method, then rinse and repeat.

Can thread pool be reused?

The technique of thread pooling allows threads to be reused to reduce thread creation overhead or when creating an unbounded number of threads can diminish the reliability of the system.

How does thread pool keeps the thread alive?

Instead of creating new threads when new tasks arrive, a thread pool keeps a number of idle threads that are ready for executing tasks as needed. After a thread completes execution of a task, it does not die. Instead it remains idle in the pool waiting to be chosen for executing new tasks.


1 Answers

It's very simple - in essence the Threads sleep, waiting to be woken by a task - they run that task and then sleep again.

public static void main(final String[] args) throws Exception {
    final BlockingQueue<Runnable> blockingQueue = new LinkedBlockingDeque<>();
    final Thread t = new Thread(new Runnable() {

        @Override
        public void run() {
            while (true) {
                try {
                    blockingQueue.take().run();
                } catch (InterruptedException ex) {
                    return;
                }
            }
        }
    });
    t.start();
    blockingQueue.add(new Runnable() {

        @Override
        public void run() {
            System.out.println("Task 1");
        }
    });
    blockingQueue.add(new Runnable() {

        @Override
        public void run() {
            System.out.println("Task 2");
        }
    });
}

The BlockingQueue will block a Thread while it is empty. When I add an item, and Thread(s) currently blocked are awoken and one will take the task (LinkedBlockingDeque is thread safe). When the Thread is done with the task it goes back to sleep.

The JavaDoc for ThreadPoolExecutor describes the logic in detail. All of the constructors for ThreadPoolExecutor take a BlockingQueue<Runnable> - this should give you a hint as so how the logic works.

NB: This is not the same as busy waiting. A BlockingQueue uses wait and notify to suspend and wake Threads, this means that the Threads in the pool are not doing any work when they are not processing tasks. A busy wait based approach would not work because the Threads would block up all the CPU cores with their polling not allowing the program to proceed (or at least severely impairing it).

like image 176
Boris the Spider Avatar answered Nov 12 '22 21:11

Boris the Spider