ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor extends ThreadPoolExecutor and implements the ScheduledExecutorService interface. It provides a more flexible way to execute delayed and periodic tasks compared to the legacy Timer class.
Source Code #
Canonical Usage #
When to use: Use ScheduledThreadPoolExecutor whenever you need to execute tasks that should run after a specific delay, or when you need tasks to run periodically (e.g., refreshing a cache every hour, sending a heartbeat signal every 10 seconds).
Common Patterns:
- Delayed Task Execution: Run a task once after a specific amount of time has passed.
- Fixed-Rate Scheduling: Task starts every
nseconds, regardless of how long the previous task took (useful for tasks that need to stay on a strict schedule). - Fixed-Delay Scheduling: Task starts
nseconds after the previous task has finished (useful for tasks that shouldn’t overlap).
// One-shot delayed task
scheduledExecutor.schedule(() -> {
System.out.println("Refreshing cache...");
cache.refresh();
}, 5, TimeUnit.MINUTES);
// Fixed-rate task (starts every hour)
scheduledExecutor.scheduleAtFixedRate(() -> {
System.out.println("Sending periodic metrics...");
metricsService.send();
}, 0, 1, TimeUnit.HOURS);
// Fixed-delay task (starts 10 seconds after previous task ends)
scheduledExecutor.scheduleWithFixedDelay(() -> {
System.out.println("Scanning for new files...");
fileScanner.scan();
}, 1, 10, TimeUnit.SECONDS);
Internal Mechanism: DelayedWorkQueue #
The most important internal component of ScheduledThreadPoolExecutor is its specialized queue called DelayedWorkQueue. Unlike a standard BlockingQueue, this is a heap-based priority queue that keeps the next task to be executed at the head.
static class DelayedWorkQueue extends AbstractQueue<Runnable>
implements BlockingQueue<Runnable> {
// Heap-based priority queue structure
private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
// ... leader-follower pattern ...
}
Comparison with Timer #
ScheduledThreadPoolExecutor is superior to Timer for several reasons:
- Thread Resilience: A single long-running or crashing task in a
Timerstops all subsequent tasks. - Temporal Flexibility: It can schedule tasks relative to current time or as a fixed-rate period.
- Resource Management: It supports dynamic pool resizing and task cancellation.