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
BlockingQueue
is 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 forcorePoolSize
andmaximumPoolSize
, 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
corePoolSize
is 5, meaning at least 5 threads are always active. - The maximum number of threads is limited to
maxPoolSize
, which is 10 threads. ArrayBlockingQueue
with a size of 20 prevents too many pending tasks from being enqueued at once.RejectedExecutionHandler.CallerRunsPolicy
ensures 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.