ThreadPoolExecutor provides seven core parameters that control thread pool behavior:
Core Parameters
- corePoolSize: The number of threads to keep in the pool even when idle, unless
allowCoreThreadTimeOutis enabled - maximumPoolSize: The maximum number of threads allowed in the pool
- keepAliveTime: The maximum time excess threads (beyond corePoolSize) remain idle before termination
- unit: Time unit for keepAliveTime
- workQueue: Queue holding tasks before execution, accepting only Runnable tasks submitted via execute()
- threadFactory: Factory for creating new threads, useful for custom naming
- handler: Rejection policy when thread bounds and queue capacity are reached
Among these, corePoolSize, maximumPoolSize, and workQueue are the most critical for custom thread pools.
The Problem with Static Configuration
Traditional approaches recommend different configurations based on task types:
- CPU-intensive tasks: corePoolSize = CPU cores + 1
- IO-intensive tasks: corePoolSize = 2 × CPU cores
However, these formulas often fail in production because:
- Task characteristics vary significantly
- Traffic patterns fluctuate throughout the day
- Fixed configurations cannot adapt to changing load conditions
Dynamic Parameter Adjustment
ThreadPoolExecutor supports runtime modification of core parameters:
Modifying Core and Maximum Pool Size
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // corePoolSize
5, // maximumPoolSize
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
new ThreadPoolExecutor.CallerRunsPolicy()
);
// Dynamically adjust pool sizes at runtime
executor.setCorePoolSize(10);
executor.setMaximumPoolSize(10);
The setCorePoolSize method handles worker threads intelligently:
- If new value < current workers: excess idle workers receive interrupt requests
- If new value > current value and queue has pending tasks: new worker threads are created
Common Pitfall: Core Size Adjustment Ineffective
A frequent issue occurs when adjusting corePoolSize alone:
// This may NOT work as expected
executor.setCorePoolSize(10); // Only adjusts core size
// Active threads remain at maximumPoolSize
The solution is to set both parameters together:
// Set both to ensure active thread count increases
executor.setCorePoolSize(10);
executor.setMaximumPoolSize(10);
When allowCoreThreadTimeOut is set to true, core threads are subject to the same idle timeout as non-core threads:
executor.allowCoreThreadTimeOut(true);
Dynamic Queue Capacity
Unlike core and maximum pool sizes, queue capacity cannot be modified directly because LinkedBlockingQueue uses a final capacity field. The solution involves creating a custom resizable queue:
public class ResizableLinkedBlockingQueue<E> extends LinkedBlockingQueue<E> {
private volatile int capacity;
public ResizableLinkedBlockingQueue(int capacity) {
super(capacity);
this.capacity = capacity;
}
@Override
public int remainingCapacity() {
return capacity;
}
public void setCapacity(int newCapacity) {
this.capacity = newCapacity;
}
public int getCapacity() {
return capacity;
}
}
Integration example:
ResizableLinkedBlockingQueue<Runnable> queue = new ResizableLinkedBlockingQueue<>(10);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 5, 60L, TimeUnit.SECONDS, queue,
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
// Dynamically resize queue at runtime
queue.setCapacity(100);
System.out.println("Queue capacity: " + queue.getCapacity());
Thread Pool Pre-warming
When a thread pool is created, no threads exist until tasks are submitted. Pre-warming ensures threads are ready:
// Start all core threads
executor.prestartAllCoreThreads();
// Or start just one core thread
executor.prestartCoreThread();
Interview Questions
Q: Does a newly created thread pool have any threads?
A: No, threads are created on-demand. Use prestartCoreThread() or prestartAllCoreThreads() for pre-warming.
Q: Can core threads be recycled?
A: By default, no. Call allowCoreThreadTimeOut(true) to enable core thread timeout, allowing回收 after keepAliveTime of idle period.
Practical Considerations
Dynamic adjustment enables rapid response to traffic spikes and traffic drops without service restart. However, monitor the following:
- Avoid setting extremely high values that could exhaust system resources
- Consider business load patterns when adjusting parameters
- Use thread factory to set meaningful thread names for debugging
- Choose appropriate rejection policies based on业务 requirements