Using a Thread Pool
A thread pool is a group of threads that run in an infinite loop and reuse a fixed number of threads to handle multiple connections.
A Server With Many Short Visits
Imagine a server that handles many clients over its lifetime. Each client connects, asks for something, and leaves. Many of these visits are brief, lasting only a moment. The server has to accept every one of them and do the work each connection needs, and it has to do this again and again. How the server organizes its threads for that job has a large effect on how efficiently it runs.
Before reading on, try to answer this for yourself: if every incoming connection gets its own brand-new thread, what work does the server repeat over and over, even when the connection itself needs very little time?
Why One Thread per Connection Costs Too Much
A simple design gives every incoming connection its own new thread. That design works, but the source points out a cost: it is not very efficient to create a new thread for every connection, especially when the connections are typically very short-lived. If each connection lasts only a moment, the server spends a meaningful share of its effort starting and stopping threads rather than doing the work the connections need.
The left column shows the cost the source describes: each connection pays for creating a thread and then for that thread finishing. The right column shows the alternative. The threads are created once and then stay available, so the cost of making threads is paid for the pool instead of being repeated for every connection.
How a Fixed Pool Reuses Its Threads
A thread pool is a group of threads that run in an infinite loop and reuse a fixed number of threads to handle multiple connections.
The key word in that definition is reuse. The pool does not grow with the number of connections. Its threads are created once and stay available. Each thread in the pool runs in an infinite loop, and each time through that loop it handles one connection. When one connection finishes, the same thread goes back around the loop and is ready for the next one.
This is where the efficiency comes from. The number of threads stays the same no matter how many connections arrive over time, and each thread is used for many connections in turn.
Tracing the Handoff Through connectionQueue
A pool of waiting threads is only useful if the main program can hand them work. The chosen tool is a blocking queue, named connectionQueue in the course's example. The main program places each new connection into this queue, and the connection-handling threads take connections out of it. The main program does not need to know which pool thread will handle a given connection; it only needs to put the connection into the queue.
Read the diagram from top to bottom. The main program is the only producer, placing connections into connectionQueue. Each connection leaves the queue once and is taken by exactly one pool thread. The pool threads are the consumers, and each of them takes the next connection when it is free to do so.
What a Pool Thread Does When the Queue Is Empty
The word blocking matters. A blocking queue is defined as a queue that blocks a thread when it is empty and wakes it up when an item becomes available. So a connection-handling thread that finds connectionQueue empty does not spin or keep checking in a tight loop. It waits, and it resumes when a connection is placed in the queue.
What do you think happens?
A pool thread has finished its last connection and loops back. This time connectionQueue has nothing in it. What does the thread do next?
Reveal answer
The thread blocks, meaning it waits without spinning. When a connection is placed in connectionQueue, the thread is woken up and resumes to take that connection.
A blocking queue makes a thread block when the queue is empty and wakes it when a connection becomes available. The thread does not need to poll the queue repeatedly, because the waiting and waking are handled by the queue itself.
The diagram traces one full cycle. A thread runs while it handles a connection, loops back when that connection finishes, and blocks if the queue has nothing for it. The only event that moves it out of the blocked state is a connection arriving in the queue. The thread does not need to be recreated for that new connection; it is the same thread, now woken up.
Following Three Connections Through Two Threads
Three connections, two pool threads
A pool has two threads, T1 and T2, both waiting on the empty connectionQueue. Three connections, C1, C2 and C3, arrive in that order. Trace which thread handles each connection and what happens to the threads afterward. This scenario is an illustration written for this article, not an example from the source.
- 1Start
Both T1 and T2 are blocked, because
connectionQueueis empty. - 2C1 arrives
The main program places C1 into
connectionQueue. The queue wakes a waiting thread, here T1, which takes C1 and runs it. - 3C2 arrives
The main program places C2 into the queue. T2 is still waiting, so it is woken and takes C2.
- 4C3 arrives
Both threads are busy, so C3 waits in
connectionQueue. Nothing is lost, and no new thread is created. - 5T1 finishes C1
T1 loops back, finds C3 in the queue, takes it, and handles it. T1 is reused for a third connection.
Two fixed threads handled three connections. The third connection was not given a new thread; it was handled by a thread that had already finished its earlier work.
Mistakes Learners Make About Pools
The ideas in a thread pool are simple to state but easy to misread. The following mistakes come up often when learners first explain how the pool works.
Common mistake Believing the pool creates a new thread for each connection
Why it failsThe defining feature of a pool is that it reuses a fixed number of threads. The threads are created once and stay available, and each one handles many connections over time.
Do this insteadThink of each pool thread as a long-lived worker that loops, not as a disposable thread for a single connection.
Common mistake Assuming an idle pool thread keeps checking the queue in a tight loop
Why it failsA blocking queue blocks a thread when it is empty. The thread waits and is woken when an item becomes available, so it does not spin or poll.
Do this insteadWhen connectionQueue is empty, picture the thread as waiting, not as busy-checking.
Common mistake Expecting the main program to choose which pool thread handles each connection
Why it failsThe main program places connections into
connectionQueue, and the pool threads take connections out of it. The main program only needs to put the connection in the queue.Do this insteadDescribe the handoff as the main program producing into the queue and the pool threads consuming from it.
Common mistake Adding extra locks or signals to the handoff when the blocking queue already coordinates it
Checking Your Understanding of the Handoff
A server with a pool of four threads receives 100 short-lived connections over an hour. Explain, in your own words, how the same four threads can serve all 100 connections, and name the component that makes a waiting thread resume when a new connection arrives.
Hints
- Think about what the pool thread does after finishing one connection.
- The component that moves a thread from waiting to running is the blocking queue, named
connectionQueuein the course example.
Key Takeaways From the Pool Design
- Creating a new thread for every connection is inefficient, especially when connections are short-lived.
- A thread pool is a group of threads that run in an infinite loop and reuse a fixed number of threads to handle multiple connections.
- The main program places connections into a blocking queue named
connectionQueue, and pool threads take connections out of it. - A blocking queue makes a thread block when the queue is empty and wakes it when a connection becomes available, so no other synchronization is needed.
At a glance
- Creating a new thread for every connection is inefficient, especially when connections are short-lived.
- A thread pool reuses a fixed number of threads, each running in an infinite loop and handling one connection after another.
- The main program hands connections to pool threads through the blocking queue
connectionQueue. - When
connectionQueueis empty, a pool thread blocks and resumes when a connection is placed in the queue.