Java Scheduling

Rashmi Patidar Oct 12, 2023
  1. Schedule a Process Using the ScheduledExecutorService Interface Methods in Java
  2. Schedule a Thread Using the Timer Class in Java
Java Scheduling

Scheduling is the process of executing a task or a function at a fixed interval of time. Scheduling finds its usage in running batch processes, sending event-based triggers like birthday wishes, sending push notifications. These processes must run at a well-defined time based on the conditions and time-interval given.

Schedule a Process Using the ScheduledExecutorService Interface Methods in Java

package scheduling;

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

public class ScheduleTask {
  private static int counter = 0;

  public static void main(String[] args) throws InterruptedException {
    ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
    Runnable executeTask = () -> {
      counter++;
      System.out.println("Task" + counter);
    };

    ScheduledFuture<?> scheduleAtFixedRate =
        service.scheduleAtFixedRate(executeTask, 5, 1, TimeUnit.SECONDS);

    while (true) {
      Thread.sleep(1000);
      if (counter == 5) {
        System.out.println("Stopping the scheduled task!");
        scheduleAtFixedRate.cancel(true);
        service.shutdown();
        break;
      }
    }
  }
}

In the above code, first, a static counter variable is initialized to zero value. The newScheduledThreadPool is a static method of the Executors class. The method creates a thread pool that should execute periodically with the parameter given in the argument list. So in our case, a single thread is created for execution as the parameter in the argument list of methods defines the number of thread pools. The method returns an instance of ScheduledExecutorService that gets stored in the service reference variable and throws IllegalArgumentException if the pool size is less than zero.

The Runnable is an interface that any class can extend and is the functional interface. It has only one static method as the run method and is intended for the thread to execute. Using the lambda expression expressed as the symbol ()-> parenthesis and an arrow, the structure states that we are not passing any arguments to the run method. We have defined the statements in the definition of the run method. The statement present inside the block will increment the counter variable and print the task in the console output. These all statements are referenced by the variable called the executeTask variable.

The service reference variable calls scheduleAtFixedRate method of ScheduledExecutorService interface. The method creates and executes the periodic task that should execute after the initial delay and later within the given period. It takes four parameters, a runnable command that is supposed to execute, and initialDelay variable is the time to delay first execution, period denotes the duration between successive executions, and unit is the unit of time in seconds, minutes, and hours. The thread starts executing as soon as the method gets called.

In the while loop, first, the current running thread is forced to sleep. Thread.sleep() method temporarily halts the currently executing thread for the defined time. The parameter is the number in milliseconds for which the current working thread should get halt. The method throws IllegalArgumentException if the value is negative and InterruptedException if the current thread is interrupted. Later a counter’s value is checked with a defined value. This check is applied to run the while method for a definite number of times. Otherwise, the block will operate for an infinite number that will never terminate. Into the while block, the scheduleAtFixedRate variable calls the cancel method, which cancels the current execution of the thread. The function also takes a Boolean parameter indicating whether the current running thread may interrupt or not.

The method service.shutdown initiates the shutdown process in which previously submitted tasks are supposed to get executed, and nothing new is accepted.

The output of the above code block is as below.

Task1
Task2
Task3
Task4
Task5
Stopping the scheduled task!

Schedule a Thread Using the Timer Class in Java

Below is the simple code block that instantiates two user-defined class objects using its constructors. TimerImplementation is the user-defined class for the same. An instance of Timer gets created that will create a new thread. The newly created object of a timer will then call the scheduleAtFixedRate method. This method takes parameters as task that needs to schedule, delay delays the task in milliseconds, and period is the time in milliseconds for successive execution.

package timer;

import java.util.Timer;

public class UsingTimerClass {
  public static void main(String[] args) {
    TimerImplementation timer1 = new TimerImplementation("Thread1");
    TimerImplementation timer2 = new TimerImplementation("Thread2");

    Timer t = new Timer();
    t.scheduleAtFixedRate(timer1, 0, 2000);
    t.scheduleAtFixedRate(timer2, 0, 1000);
  }
}

Below is the implementation of the user-defined class. The TimerImplementation class extends the TimerTask abstract class that holds a single abstract method named run. We extend the TimerTask class in a user-defined class then the run method gets overridden.

The class has one user-defined constructor that sets the user-defined name to the thread object.

We can give actual logic in the thread run method. It includes a statement as print which will print the name of the currently executing thread. Thread.currentThread().getName() returns the name of current executing thread. The sleep method gets called over Thread1 that interrupts the execution for 1000 milliseconds. The sleep method throws InterruptedException if any thread interrupts the current thread, and that’s why it gets enclosed in the try-catch block.

package timer;

import java.util.TimerTask;

public class TimerImplementation extends TimerTask {
  private String name;

  public TimerImplementation(String n) {
    this.name = n;
  }

  @Override
  public void run() {
    System.out.println(Thread.currentThread().getName() + " " + name);
    if ("Thread1".equalsIgnoreCase(name)) {
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
}

Below is the never-ending output of the above code. Since we have not defined any terminating condition in the run method, the thread will execute endlessly until an external stop is applied to kill the main thread execution.

Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Timer-0 Thread2
Timer-0 Thread1
Timer-0 Thread2
Rashmi Patidar avatar Rashmi Patidar avatar

Rashmi is a professional Software Developer with hands on over varied tech stack. She has been working on Java, Springboot, Microservices, Typescript, MySQL, Graphql and more. She loves to spread knowledge via her writings. She is keen taking up new things and adopt in her career.

LinkedIn