Java > Concurrency and Multithreading > Executors and Thread Pools > Scheduled Executors
ScheduledExecutorService Example: Delayed Task Execution
This example demonstrates how to use `ScheduledExecutorService` to schedule a task to run after a specified delay. It's useful for situations where you need to execute a piece of code after a certain amount of time has elapsed.
Code Snippet
This code snippet uses `Executors.newScheduledThreadPool(1)` to create a `ScheduledExecutorService` with a pool size of 1. It then defines a `Runnable` task that prints the current timestamp to the console. The `scheduler.schedule(task, 5, TimeUnit.SECONDS)` method schedules the task to run after a 5-second delay. Finally, the `scheduler.shutdown()` method is called to prevent new tasks from being submitted, and `scheduler.awaitTermination` is used to wait for existing tasks to complete.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
System.out.println("Task executed at: " + System.currentTimeMillis() / 1000);
};
System.out.println("Scheduling task for execution after 5 seconds...");
scheduler.schedule(task, 5, TimeUnit.SECONDS);
scheduler.shutdown(); // Prevents new tasks from being submitted
// scheduler.shutdownNow(); // Attempts to stop all actively executing tasks, halts the processing of waiting tasks, and returns a list of the tasks that were awaiting execution.
try {
scheduler.awaitTermination(10, TimeUnit.SECONDS); // Wait for up to 10 seconds for the executor to finish existing tasks
} catch (InterruptedException e) {
System.err.println("Interrupted while waiting for termination: " + e.getMessage());
}
}
}
Concepts Behind the Snippet
ScheduledExecutorService
allows you to schedule tasks to run either after a delay or periodically. It extends the ExecutorService
interface and provides methods for scheduling tasks with different execution policies. The schedule()
method is used for delayed execution, while scheduleAtFixedRate()
and scheduleWithFixedDelay()
are used for periodic execution. Thread pools are essential for efficiently managing threads and preventing resource exhaustion.
Real-Life Use Case
Scheduled executors are frequently used in applications that require background tasks to be executed at regular intervals, such as:
Best Practices
ScheduledExecutorService
when it's no longer needed to release resources. Use shutdown()
followed by awaitTermination()
for graceful shutdown.
scheduleAtFixedRate()
and scheduleWithFixedDelay()
and choose the method that best suits your needs.
Interview Tip
Be prepared to discuss the difference between scheduleAtFixedRate()
and scheduleWithFixedDelay()
. The former executes tasks at a fixed rate, regardless of how long the previous execution took, while the latter executes tasks with a fixed delay between the end of the previous execution and the start of the next. Also, understand the implications of handling exceptions within scheduled tasks.
When to use them
Use ScheduledExecutorService
when you need to execute tasks at specific times or intervals. This is preferred over using Timer
or creating your own threads with sleeps, as it provides better thread management and exception handling.
Memory Footprint
The memory footprint of a ScheduledExecutorService
depends on the number of threads in the pool and the number of scheduled tasks. Each thread consumes memory for its stack and other resources. Scheduled tasks consume memory for the task itself and any associated data. Carefully consider the number of threads and scheduled tasks to avoid excessive memory consumption.
Alternatives
Timer
class can be used for similar tasks, but it has some drawbacks compared to ScheduledExecutorService
, such as running all tasks in a single thread and being less robust in handling exceptions.TaskScheduler
interface provides a convenient way to schedule tasks.
Pros
Timer
.
Cons
Timer
.
FAQ
-
What's the difference between `scheduleAtFixedRate` and `scheduleWithFixedDelay`?
`scheduleAtFixedRate` executes tasks at a fixed rate, regardless of the execution time of the previous task. `scheduleWithFixedDelay` executes tasks with a fixed delay between the end of the previous execution and the start of the next. -
How do I handle exceptions in scheduled tasks?
Wrap the task's code in a `try-catch` block to catch and handle exceptions. Log the exceptions or perform other appropriate actions to prevent them from terminating the task. -
Why should I call `shutdown()` on the `ScheduledExecutorService`?
Calling `shutdown()` prevents new tasks from being submitted to the executor. This is important to ensure that the application terminates gracefully when it's no longer needed. Without calling `shutdown()`, the executor's threads may prevent the JVM from exiting.