User Tools

Site Tools


java:threadpoolexecutor

This is an old revision of the document!


ThreadPoolExecutor

This class is used to execute tasks in Java. Generally, users will not directly create a ThreadPoolExecutor, but instead use one of the the static factory methods in `Executors` to create one. For example:

  1. class Runner {
  2.  
  3. private final ExecutorService executor = Executors.newCachedThreadPool();
  4.  
  5. public void run(Runnable r) {
  6. executor.execute(r);
  7. }
  8. }

Implementation

ThreadPoolExecutor is implemented by two sets of queues:

  1. The task queue. This is a |BlockingQueue that stores pending tasks. When calls to `submit()` or `executor()` are made, the tasks are added to this queue.
  2. The thread queue. This queue is less visible. ThreadPoolExecutor maintains several threads, which each try to pull tasks off the task queue. In an executor with a fixed number of threads (e.g. newFixedThreadPool()), each thread tries to pull an item off the queue and execute it.

If there are no items to take off the task queue, the threads wait to try and take the next item that gets added. In this way, they form a natural queue, each waiting in line to get the next task to execute.

When submitting a work item to a ThreadPoolExecutor, the caller tries to add the item to the task queue. What happens if there is no room on the task queue? ThreadPoolExecutor tries to spawn a new thread to accept the new task. The behavior here is different depending on the core pool size.

  • In a cached ThreadPoolExecutor, the core pool size is 0 and the task queue is permanently empty. When a caller tries to submit a task, there is no space in the queue. This is due to the task queue being a `SynchronousQueue`, which requires a consuming thread to be listening on it. Because the caller cannot add the item to the queue, and because the core pool size is less than the max pool size, ThreadPoolExecutor spawns a new thread to handle the additional task.
  • In a fixed ThreadPoolExecutor, the core pool size is N where N was set at instantiation. When a caller tries to submit a task, the task is added to a (usually unbounded) task queue, and then consumed by one of the N threads later.

As we can see, the core pool size has an intricate interplay with the task queue. By constraining the task queue, we can make ThreadPoolExecutor spawn more threads, up to the maximum. By unbounding the task queue, we can limit the number of threads handling tasks. By default, a cached threadpool is both an unlimited number of thread, and a limited task queue. A fixed threadpool is an unlimitted number of tasks, and a limited thread pool. The constructor overloads of ThreadPoolExecutor let us customize this even more, but these are the most common cases. The behavior of the pool is a consequence of the task queue and thread spawning rules.

java/threadpoolexecutor.1740211349.txt.gz · Last modified: by carl