How do I schedule tasks using ScheduledExecutorService?

The ScheduledExecutorService is a Java concurrency utility used for scheduling tasks to run after a delay or to execute periodically. Introduced in Java 5 as part of the java.util.concurrent package, it provides flexible scheduling functionality.
Here’s how you can use it:

1. Getting an Instance of ScheduledExecutorService

You can obtain an instance using the Executors factory class:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

// Single-threaded scheduled executor
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);  

2. Methods to Schedule Tasks

A) Schedule a Task with a Delay

To schedule a task to execute once after a specified delay:

import java.util.concurrent.TimeUnit;

scheduler.schedule(() -> {
    System.out.println("Task executed after delay");
}, 5, TimeUnit.SECONDS);

In this example:

  • A task will run after a delay of 5 seconds.

B) Schedule a Task at Fixed Rate

To schedule a task to run repeatedly at a fixed rate, starting after an initial delay:

scheduler.scheduleAtFixedRate(() -> {
    System.out.println("Task executed at fixed rate");
}, 2, 3, TimeUnit.SECONDS);

In this example:

  • The task will first execute 2 seconds after scheduling.
  • Subsequent executions will occur every 3 seconds, irrespective of the previous task’s runtime.

C) Schedule a Task with Fixed Delay

To schedule a task to run repeatedly with a fixed delay between the completion of one execution and the start of the next:

scheduler.scheduleWithFixedDelay(() -> {
    System.out.println("Task executed with fixed delay");
}, 2, 3, TimeUnit.SECONDS);

In this example:

  • The task will first execute 2 seconds after scheduling.
  • Subsequent executions will occur 3 seconds after the previous task finishes.

3. Shutting Down the Scheduler

It’s important to properly shut down the scheduler to release resources when it is no longer needed:

scheduler.shutdown();

If you want to wait for currently executing tasks to finish before termination:

try {
    if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
        scheduler.shutdownNow();  // Forcefully shutdown if tasks don't complete within 60 seconds
    }
} catch (InterruptedException e) {
    scheduler.shutdownNow();
}

4. Example: Complete Program

Here’s a complete program demonstrating all of the above:

package org.kodejava.util.concurrent;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorExample {
    public static void main(String[] args) {
        // Create a ScheduledExecutorService with a single thread
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

        // Schedule a task to run after a delay
        scheduler.schedule(() -> System.out.println("Task1 executed after 5 seconds"), 5, TimeUnit.SECONDS);

        // Schedule a task to run periodically at a fixed rate
        scheduler.scheduleAtFixedRate(() -> System.out.println("Task2 executed at fixed rate"), 2, 3, TimeUnit.SECONDS);

        // Schedule a task to run periodically with a fixed delay
        scheduler.scheduleWithFixedDelay(() -> System.out.println("Task3 executed with fixed delay"), 2, 5, TimeUnit.SECONDS);

        // Shut down the scheduler after some time for demonstration
        scheduler.schedule(() -> {
            System.out.println("Shutting down scheduler...");
            scheduler.shutdown();
        }, 20, TimeUnit.SECONDS);
    }
}

Key Points to Remember

  • Use scheduleAtFixedRate for periodic tasks that need to run at a consistent interval irrespective of the task runtime.
  • Use scheduleWithFixedDelay when the delay between task executions must consider the runtime of the previous task.
  • Always shut down the ScheduledExecutorService to release resources.

How do I create a scheduled task using timer?

This example show you how to create a simple class for scheduling a task using Timer and TimerTask class.

package org.kodejava.util;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerExample extends TimerTask {
    private final DateFormat formatter = new SimpleDateFormat("hh:mm:ss a");

    public static void main(String[] args) {
        // Create an instance of TimerTask implementor.
        TimerTask task = new TimerExample();

        // Create a new timer to schedule the TimerExample instance at a
        // periodic time every 5000 milliseconds (5 seconds) and start it
        // immediately
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(task, new Date(), 5000);
    }

    /**
     * This method is the implementation of a contract defined in the 
     * TimerTask class. This in the entry point of the task execution.
     */
    public void run() {
        // To make the example simple we just print the current time.
        System.out.println(formatter.format(new Date()));
    }
}

Here is the result printed by the code snippet above:

09:53:28 AM
09:53:33 AM
09:53:38 AM
09:53:43 AM
09:53:48 AM