Java provides multiple mechanisms for executing a task after a certain delay. One robust modern approach is to use ScheduledExecutorService, which offfers better thread management and flexibility than the traditional Timer class. This article demonstrates how to schedule a one‑shot delayed task using this executor.
Overview: Scheduling a One‑Time Delayed Task
The process can be broken down into three clear steps:
- Create a scheduled executor service with the desired thread pool size.
- Define the task to be executed, typically as a
RunnableorCallable. - Schedule the task with a specified delay, causing it to run exact once after that period elapses.
Step‑by‑Step Implementation
1. Creating the Executor Service
Instantiate a ScheduledExecutorService using one of the factory methods from Executors. For a single delayed task, a single‑threaded executor is sufficient.
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
This executor will manage thread lifecycles and ensures tasks are run sequentially.
2. Preparign the Task Logic
Encapsulate the work you want to perform in a Runnable lambda or concrete class.
Runnable delayedOperation = () -> {
System.out.println("Delayed task executed at " + System.currentTimeMillis());
// Place your actual business logic here
};
3. Scheduling with a Fixed Delay
Use the schedule method, passing the task, the delay amount, and the time unit.
long delayMs = 1500; // 1.5 seconds
scheduler.schedule(delayedOperation, delayMs, TimeUnit.MILLISECONDS);
The method returns a ScheduledFuture that can be used to cancel or query the task if needed.
Complete Working Example
Below is a self‑contained program that prints a startup message, schedules a task to run after 2 seconds, and then shuts down the executor gracefully.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DelayedTaskDemo {
public static void main(String[] args) throws InterruptedException {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
Runnable task = () -> {
System.out.println("Task completed after delay.");
};
long initialDelay = 2000; // milliseconds
System.out.println("Scheduling task to run in " + initialDelay + " ms...");
scheduler.schedule(task, initialDelay, TimeUnit.MILLISECONDS);
// Allow the scheduled task to execute before shutdown
scheduler.shutdown();
scheduler.awaitTermination(3, TimeUnit.SECONDS);
System.out.println("Scheduler terminated.");
}
}
After the delay, the message Task completed after delay. appears, confirming that the waiting period was respected.
Advantages over java.util.Timer
- Thread pooling: ScheduledExecutorService can reuse threads, reducing overhead.
- Exception handling: A failed task does not cause the entire scheduler to stop.
- Flexibility: You can schedule tasks with fixed delays or at fixed rates, and obtain a
Futurefor control.