Managed thread pools with monitoring and graceful shutdown for Java applications.
- Configurable Thread Pools: Flexible core/max pool sizes, queue capacity, and keep-alive times
- Thread Naming: Automatic thread naming with application ID for easy identification in thread dumps
- Exception Handling: Uncaught exception handler that logs errors
- Statistics Tracking: Real-time pool statistics (active threads, completed tasks, queue size)
- Graceful Shutdown: Configurable shutdown with timeout and force shutdown fallback
- AutoCloseable: Implements AutoCloseable for try-with-resources support
- CallerRunsPolicy: Rejected tasks run in calling thread to prevent task loss
<dependency>
<groupId>org.flossware</groupId>
<artifactId>jthreadpool</artifactId>
<version>1.0</version>
</dependency>implementation 'org.flossware:jthreadpool:1.0'import org.flossware.jthreadpool.*;
// Create thread pool configuration
ThreadPoolConfig config = ThreadPoolConfig.builder()
.corePoolSize(4)
.maxPoolSize(8)
.keepAliveTimeSeconds(60)
.queueCapacity(100)
.build();
// Create managed thread pool
ManagedThreadPool pool = new ManagedThreadPool("my-app", config);
// Submit tasks
pool.submit(() -> {
System.out.println("Running in thread: " + Thread.currentThread().getName());
// Do work...
});
// When done
pool.shutdown();ThreadPoolConfig config = ThreadPoolConfig.defaultConfig();
try (ManagedThreadPool pool = new ManagedThreadPool("my-app", config)) {
pool.submit(() -> doWork());
pool.submit(() -> doMoreWork());
// Pool automatically shuts down when exiting try block
}ManagedThreadPool pool = new ManagedThreadPool("my-app", config);
// Submit some tasks
for (int i = 0; i < 10; i++) {
pool.submit(() -> doWork());
}
// Get current statistics
ThreadPoolStats stats = pool.getStats();
System.out.println("Active threads: " + stats.getActiveThreads());
System.out.println("Completed tasks: " + stats.getCompletedTasks());
System.out.println("Queued tasks: " + stats.getQueuedTasks());
System.out.println("Pool size: " + stats.getPoolSize());Future<String> future = pool.submit(() -> {
// Do some computation
return "Result";
});
String result = future.get(5, TimeUnit.SECONDS);
System.out.println("Got result: " + result);Configuration builder for thread pool settings.
Builder Methods:
corePoolSize(int)- Minimum threads to keep in pool (default: 2)maxPoolSize(int)- Maximum threads allowed in pool (default: 10)keepAliveTimeSeconds(long)- Time idle threads wait before terminating (default: 60)queueCapacity(int)- Maximum queued tasks (default: 100)build()- Build the configuration
Static Methods:
defaultConfig()- Returns configuration with default valuesbuilder()- Create new builder
Validation:
corePoolSizemust be >= 0maxPoolSizemust be > 0 and >= corePoolSizekeepAliveTimeSecondsmust be >= 0queueCapacitymust be >= 0
Main thread pool implementation with monitoring.
Constructor:
ManagedThreadPool(String applicationId, ThreadPoolConfig config)
Task Submission:
submit(Runnable)- Submit Runnable task, returns Future<?>submit(Callable<T>)- Submit Callable task, returns Futureexecute(Runnable)- Execute Runnable without Future
Lifecycle:
shutdown()- Graceful shutdown (waits up to 30 seconds)shutdownNow()- Force shutdown immediatelyisShutdown()- Check if shutdown initiatedisTerminated()- Check if all tasks completedclose()- AutoCloseable support (calls shutdown)
Monitoring:
getStats()- Get current ThreadPoolStats snapshotgetApplicationId()- Get application identifier
Thread Naming:
Threads are named as {applicationId}-thread-{N} for easy identification in thread dumps and monitoring tools.
Immutable snapshot of thread pool statistics.
Methods:
getActiveThreads()- Number of actively executing tasksgetCompletedTasks()- Total completed tasksgetQueuedTasks()- Number of tasks waiting in queuegetPoolSize()- Current number of threads in poolgetCorePoolSize()- Configured core pool sizegetMaximumPoolSize()- Configured maximum pool sizetoString()- Human-readable statistics
- Web Servers: Handle HTTP requests with bounded concurrency
- Background Processing: Execute async tasks with resource limits
- Multi-Tenant Applications: Per-tenant thread pools with isolation
- Batch Processing: Parallel task execution with controlled parallelism
- Event Processing: Asynchronous event handling
// CPU-intensive tasks: 1 thread per core
int cpuBound = Runtime.getRuntime().availableProcessors();
ThreadPoolConfig cpuConfig = ThreadPoolConfig.builder()
.corePoolSize(cpuBound)
.maxPoolSize(cpuBound)
.build();
// I/O-intensive tasks: More threads than cores
int ioBound = Runtime.getRuntime().availableProcessors() * 2;
ThreadPoolConfig ioConfig = ThreadPoolConfig.builder()
.corePoolSize(ioBound)
.maxPoolSize(ioBound * 2)
.queueCapacity(1000)
.build();ManagedThreadPool pool = new ManagedThreadPool("app", config);
// Register shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("Shutting down thread pool...");
pool.shutdown();
}));Uncaught exceptions in tasks are automatically logged:
pool.submit(() -> {
throw new RuntimeException("Task failed");
// Automatically logged: [app-id] Uncaught exception in thread app-id-thread-1
});ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor();
monitor.scheduleAtFixedRate(() -> {
ThreadPoolStats stats = pool.getStats();
logger.info("Pool stats: {}", stats);
// Alert if queue is growing
if (stats.getQueuedTasks() > 80) {
logger.warn("Thread pool queue filling up!");
}
}, 0, 30, TimeUnit.SECONDS);- Bounded Resources: Configurable limits prevent resource exhaustion
- Fail-Safe: CallerRunsPolicy prevents task rejection
- Observable: Real-time statistics for monitoring
- Lifecycle Management: Clear shutdown semantics
- Thread Safety: All operations are thread-safe
- Java 21 or higher
- SLF4J API (for logging)
MIT License - see LICENSE file for details.
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
See CHANGELOG.md for version history.