To throttle concurrent threads using ThreadPoolExecutor settings in Java, you can configure its key parameters: core pool size, maximum pool size, and queue capacity. These settings control how ThreadPoolExecutor manages the number of concurrently running threads and queued tasks.
Explanation of Key ThreadPoolExecutor Settings:
- Core Pool Size:
- This defines the number of threads that are kept in the pool even when they are idle.
- If the number of actively running threads is less than the core pool size, a new thread is created to handle a task, even if there are idle threads.
- Maximum Pool Size:
- This is the maximum number of threads that can exist in the pool.
- If the pool reaches this limit, tasks are queued instead of creating new threads.
- Queue Capacity:
- A
BlockingQueueis used to hold tasks that are waiting to execute. - If the queue is full and the number of active threads is already at the maximum pool size, new tasks will be rejected according to the specified
RejectedExecutionHandler.
- A
By adjusting these parameters, you can throttle the number of active threads, controlling concurrency.
Steps to Throttle Threads:
- Use a Fixed Maximum Pool Size:
Set a value forcorePoolSizeandmaximumPoolSize, controlling the maximum number of threads allowed to execute concurrently. -
Configure the Queue Size:
Use a bounded queue (e.g.,ArrayBlockingQueue) with a fixed size to limit the number of pending tasks. Once the queue is full, no additional tasks will be accepted unless threads become available. -
Avoid Overloading the System:
Ensure that the total number of threads and tasks in the queue doesn’t overwhelm system resources like CPU or memory.
Example Solution:
package org.kodejava.util.concurrent;
import java.util.concurrent.*;
public class ThreadPoolThrottle {
public static void main(String[] args) {
// Define Executor settings
int corePoolSize = 5; // Minimum threads
int maxPoolSize = 10; // Maximum threads
int queueCapacity = 20; // Queue size
long keepAliveTime = 1; // Threads idle time in seconds
// Create a ThreadPoolExecutor
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize,
maxPoolSize,
keepAliveTime,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(queueCapacity),
new ThreadPoolExecutor.CallerRunsPolicy() // Rejected tasks run in the caller thread
);
// Submit tasks to throttle
for (int i = 0; i < 50; i++) {
final int taskID = i;
executor.execute(() -> {
try {
System.out.println("Task " + taskID + " is running");
Thread.sleep(1000); // Simulate work
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
// Shut down the executor
executor.shutdown();
}
}
Key Points in the Example:
- The
corePoolSizeis 5, meaning at least 5 threads are always active. - The maximum number of threads is limited to
maxPoolSize, which is 10 threads. ArrayBlockingQueuewith a size of 20 prevents too many pending tasks from being enqueued at once.RejectedExecutionHandler.CallerRunsPolicyensures that tasks are executed in the caller thread when the queue is full, preventing silent task rejection.
Resulting Throttling Behavior:
- No more than 10 threads will run concurrently.
- A maximum of 20 tasks will be queued at any time.
- Tasks beyond the queue/throttle limit are forced to run in the caller thread or handled by a custom rejection policy.
By tweaking these settings, you can fine-tune thread throttling behavior for specific performance and resource requirements.
