Learnitweb

ScheduledThreadPoolExecutor in Java

1. What is a ScheduledThreadPoolExecutor?

ScheduledThreadPoolExecutor is a part of Java’s java.util.concurrent package. It allows you to schedule tasks to run after a delay or periodically, using a pool of threads.

It is a powerful replacement for the older Timer and TimerTask classes, offering:

  • Better performance
  • More robust error handling
  • Flexible thread pool management
  • Fine-grained control over scheduling

2. Where is it defined?

java.util.concurrent.ScheduledThreadPoolExecutor

It implements:

  • ScheduledExecutorService
  • ExecutorService

2. Why use ScheduledThreadPoolExecutor instead of Timer?

FeatureScheduledThreadPoolExecutorTimer
Uses thread poolYesNo (single thread only)
Handles multiple tasksConcurrentlySequentially
Exception handlingBetter — doesn’t halt on exceptionOne exception can stop the timer
SchedulingFixed delay or fixed rateOnly fixed delay
Thread managementScalable and configurableRigid

3. How to Create a ScheduledThreadPoolExecutor

Option 1: Direct constructor

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(4);

4 means it can run 4 scheduled tasks concurrently.

Option 2: Using Executors factory

ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);

Returns a ScheduledExecutorService, which is the interface.

4. Scheduling Methods

The following are the most commonly used methods for scheduling tasks:

A. schedule(Runnable command, long delay, TimeUnit unit)

Schedules a one-time task after a delay.

executor.schedule(() -> System.out.println("Task runs after 3 seconds"), 3, TimeUnit.SECONDS);

B. scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

  • Schedules a task to run repeatedly:
    • Starts after initialDelay
    • Then runs every period regardless of how long the task takes
  • If a task runs longer than the period, tasks may overlap.
executor.scheduleAtFixedRate(() -> System.out.println("Fixed Rate Task"), 1, 2, TimeUnit.SECONDS);

C. scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

Schedules a task to run repeatedly:

  • Starts after initialDelay
  • Each execution is delayed by delay after the previous run completes

Ensures no overlap.

executor.scheduleWithFixedDelay(() -> System.out.println("Fixed Delay Task"), 1, 2, TimeUnit.SECONDS);

5. Example: One-Time and Repeating Tasks

import java.util.concurrent.*;

public class ScheduledExecutorExample {
    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

        // One-time task
        executor.schedule(() -> System.out.println("Run once after 3 seconds"), 3, TimeUnit.SECONDS);

        // Fixed-rate task
        executor.scheduleAtFixedRate(() -> {
            System.out.println("Fixed rate: " + System.currentTimeMillis());
        }, 1, 5, TimeUnit.SECONDS);

        // Fixed-delay task
        executor.scheduleWithFixedDelay(() -> {
            System.out.println("Fixed delay: " + System.currentTimeMillis());
        }, 1, 5, TimeUnit.SECONDS);
    }
}

6. Shutting Down the Executor

It’s important to shut down the executor to release resources:

executor.shutdown(); // Waits for tasks to finish
executor.shutdownNow(); // Attempts to stop all tasks immediately

You can also use awaitTermination() to wait:

executor.awaitTermination(10, TimeUnit.SECONDS);

7. Handling Exceptions in Tasks

If a task throws an unchecked exception, it will be suppressed silently. You must handle exceptions inside the task:

executor.schedule(() -> {
    try {
        // risky logic
    } catch (Exception e) {
        e.printStackTrace();
    }
}, 1, TimeUnit.SECONDS);

8. Use Cases

  • Periodic status polling (e.g., database, sensors)
  • Repeating background jobs (e.g., email reminders)
  • Time-based cache eviction
  • System health monitoring
  • One-time delayed actions (e.g., logout timeout)

9. Best Practices

  • Always shut down the executor when done to avoid thread leaks.
  • Prefer scheduleWithFixedDelay when task duration is variable.
  • Use try-catch inside tasks to avoid silent failure.
  • Choose an appropriate thread pool size based on concurrency needs.
  • Avoid blocking tasks inside the executor (e.g., I/O or sleep), or the thread pool may exhaust.

10. Advanced: Customize ThreadPoolExecutor

You can extend ScheduledThreadPoolExecutor for custom behavior:

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2) {
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        System.out.println("About to run task: " + r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        System.out.println("Finished task: " + r);
    }
};