Friday, January 22, 2021

Java ScheduledThreadPoolExecutor - Task Scheduling in Java

Java executors framework provides an alternative to manage threads rather than using the Thread class. At the core of the executors is the Executor interface, which is extended by ExecutorService and ScheduledExecutorService interfaces. There are also pre defined executor classes that implement these interfaces like ThreadPoolExecutor class which executes the submitted task using one of the pooled thread. ThreadPoolExecutor class executes the submitted task as soon as the thread is available. If you want to schedule tasks to run after a given delay, or to execute periodically as per the configured schedule then you can use ScheduledThreadPoolExecutor class in Java.

ScheduledThreadPoolExecutor in Java

ScheduledThreadPoolExecutor class is part of the executors framework. This class extends ThreadPoolExecutor and implements ScheduledExecutorService interface. ScheduledExecutorService interface extends ExecutorService interface and provides methods for scheduling.

Instantiating a ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor class in Java provides many constructors for instantiation.

  • ScheduledThreadPoolExecutor(int corePoolSize)- Creates a new ScheduledThreadPoolExecutor with the given core pool size.
  • ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler)- Creates a new ScheduledThreadPoolExecutor with the given initial parameters.
  • ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory)- Creates a new ScheduledThreadPoolExecutor with the given initial parameters.
  • ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory, RejectedExecutionHandler handler)- Creates a new ScheduledThreadPoolExecutor with the given initial parameters.

But it is more convenient to use one of the static factory methods provided by the Executors class providing preconfigured settings for the most common usage scenarios.

  • Executors.newSingleThreadScheduledExecutor()- Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically.
  • Executors.newScheduledThreadPool(int corePoolSize)- Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.

Though these methods provide settings for the parameters but it is better to have idea of the parameters as shown in the constructor of the ScheduledThreadPoolExecutor class.

  • corePoolSize- The number of threads to keep in the pool. When a new task is submitted and number of threads running is less than the corePoolSize, a new thread is created to handle the request, even if other worker threads are idle.
  • threadFactory- New threads are created using a ThreadFactory. If not otherwise specified, a Executors.defaultThreadFactory() is used, that creates threads to all be in the same ThreadGroup and with the same NORM_PRIORITY priority and non-daemon status. By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status, etc.
  • handler- the handler to use when execution is blocked because the thread bounds and queue capacities are reached. Four predefined handler policies are provided-
    1. ThreadPoolExecutor.AbortPolicy- The handler throws a runtime RejectedExecutionException upon rejection. It is the default handler policy.
    2. ThreadPoolExecutor.CallerRunsPolicy- Handler runs the rejected task directly in the calling thread of the execute method, unless the executor has been shut down, in which case the task is discarded.
    3. ThreadPoolExecutor.DiscardPolicy- A task that cannot be executed is simply dropped.
    4. ThreadPoolExecutor.DiscardOldestPolicy- The task at the head of the work queue is dropped.

Methods for scheduling in Java ScheduledThreadPoolExecutor

The methods that execute a Runnable or Callable task after a specified delay as defined in ScheduledExecutorService interface are given below.

  • schedule(Runnable command, long delay, TimeUnit unit)- Submits a one-shot task that becomes enabled after the given delay.
  • schedule(Callable<V> callable, long delay, TimeUnit unit)- Submits a value-returning one-shot task that becomes enabled after the given delay.

In addition, the interface defines scheduleAtFixedRate and scheduleWithFixedDelay, which executes specified tasks repeatedly, at defined intervals.

  • scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)- Submits a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period. For example if initial delay is 10 sec and period is 2 sec then the execution will commence after 10 seconds and then happen periodically after every 2 seconds.
  • scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)- Submits a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.

Note that all these methods return a ScheduledFuture which is a delayed result-bearing action.

Java ScheduledThreadPoolExecutor Examples

1- In the first example schedule() method with Callable instance is used.

public class STEDemo {
  public static void main(String[] args) {
    ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(2);
    // Callable implemented as lambda
    Callable<String> c = ()->{
        System.out.println("Time of execution- " + new Date());
        return "Callable lambda is called";
    };
    System.out.println("Time before execution- " + new Date());
    // scheduling tasks with callable as param
    // it will execute after a delay of 3 Secs
    ScheduledFuture<String> sf = scheduledExecutor.schedule(c, 3, TimeUnit.SECONDS); 
    try {
      System.out.println("Value- " + sf.get());
    } catch (InterruptedException | ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
      scheduledExecutor.shutdown();
  }
}

Output

Time before execution- Wed Nov 21 11:32:56 IST 2018
Time of execution- Wed Nov 21 11:32:59 IST 2018
Value- Callable lambda is called

As you can see the task is scheduled to run after the delay of 3 seconds which is what the time before execution and time of execution confirm in the output.

2- ScheduledThreadPoolExecutor example showing periodic task scheduling using scheduleAtFixedRate() method.
public class STEDemo {
  public static void main(String[] args) {
    ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(2);
    ScheduledTask runnableTask = new ScheduledTask();
    System.out.println("Time before execution- " + new Date());
    // scheduling tasks with callable as param
    // it will execute after a delay of 2 Secs
    ScheduledFuture<?> sf = scheduledExecutor.scheduleAtFixedRate(runnableTask, 10, 2, TimeUnit.SECONDS); 
       
    try {
      // To terminate after 20 seconds
      scheduledExecutor.awaitTermination(20, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
      scheduledExecutor.shutdown();
  }
}

class ScheduledTask implements Runnable{
  @Override
  public void run() {
    //System.out.println();
    System.out.println("in run task for thread - " + Thread.currentThread().getName() + "Time of execution- " + new Date());
    // Introducing some delay for switching
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Output

Time before execution- Wed Nov 21 11:58:19 IST 2018
in run task for thread - pool-1-thread-1Time of execution- Wed Nov 21 11:58:29 IST 2018
in run task for thread - pool-1-thread-1Time of execution- Wed Nov 21 11:58:31 IST 2018
in run task for thread - pool-1-thread-1Time of execution- Wed Nov 21 11:58:33 IST 2018
in run task for thread - pool-1-thread-2Time of execution- Wed Nov 21 11:58:35 IST 2018
in run task for thread - pool-1-thread-2Time of execution- Wed Nov 21 11:58:37 IST 2018

In the code thread pool of two threads is created and a runnable task is scheduled to run periodically. In scheduleAtFixedRate method initial delay is set as 10 seconds and after that successive execution is scheduled every 2 seconds which can be confirmed from the output. From the output you can also see that both the threads from the pool are used for executing scheduled task.

3- ScheduledThreadPoolExecutor example showing periodic task scheduling using scheduleWithFixedDelay() method. With scheduleWithFixedDelay() task is first executed after initial delay and then successive execution is scheduled to happen after the termination of one execution + given delay.
public class STEDemo {
  public static void main(String[] args) {
    ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(2);
    ScheduledTask runnableTask = new ScheduledTask();
    System.out.println("Time before execution- " + new Date());
    // scheduling tasks with callable as param
    // it will execute after a delay of 2 Secs
    ScheduledFuture<?> sf = scheduledExecutor.scheduleWithFixedDelay(runnableTask, 10, 2, TimeUnit.SECONDS); 
       
    try {
      // To terminate after 20 seconds
      scheduledExecutor.awaitTermination(20, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
      scheduledExecutor.shutdown();
  }
}

class ScheduledTask implements Runnable{
  @Override
  public void run() {
    //System.out.println();
    System.out.println("in run task for thread - " + Thread.currentThread().getName() + "Time of execution- " + new Date());
    // Introducing some delay for switching
    try {
      Thread.sleep(2000);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

Output

Time before execution- Wed Nov 21 12:03:59 IST 2018
in run task for thread - pool-1-thread-1Time of execution- Wed Nov 21 12:04:09 IST 2018
in run task for thread - pool-1-thread-1Time of execution- Wed Nov 21 12:04:13 IST 2018
in run task for thread - pool-1-thread-1Time of execution- Wed Nov 21 12:04:17 IST 2018

As you can see from the output the task is successively executed every 4 seconds which is time of completion of one execution (which takes at least 2 secs as the thread sleeps for 2 secs) + delay (passed as 2 secs).

That's all for this topic Java ScheduledThreadPoolExecutor - Task Scheduling in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!


Related Topics

  1. Difference Between Runnable And Callable in Java
  2. CompletableFuture in Java With Examples
  3. Lock Striping in Java Concurrency
  4. Java DelayQueue With Examples
  5. Java Concurrency Interview Questions And Answers

You may also like-

  1. How to Loop Through HashSet in Java
  2. Difference Between HashMap And ConcurrentHashMap in Java
  3. Java ReentrantLock With Examples
  4. Java Stream flatMap() Method
  5. this Keyword in Java With Examples
  6. Switch Case Statement in Java With Examples
  7. How to Convert Date to String in Java
  8. Passing Arguments to getBean() Method in Spring