Implementing a Delayed Task Scheduler in Java

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:

  1. Create a scheduled executor service with the desired thread pool size.
  2. Define the task to be executed, typically as a Runnable or Callable.
  3. 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 Future for control.

Tags: java ScheduledExecutorService delayed execution Concurrency Runnable

Posted on Tue, 04 Aug 2026 17:01:08 +0000 by Adeus