Learn to execute a task after a period of time or execute it periodically using ScheduledExecutorService class in Java using ScheduledThreadPoolExecutor.
1. ScheduledExecutorService interface
By default, Executor
framework provides the ThreadPoolExecutor
class to execute Callable
and Runnable
tasks with a pool of threads, which helps us avoid all thread creation boiler-plate code. When we send a task to the executor, it’s executed as soon as possible, according to the configuration of the executor.
But when we are not interested in executing a task as soon as possible and want to execute a task after a period of time or do it periodically, we can use ScheduledExecutorService interface along with its implementation, namely the ScheduledThreadPoolExecutor class.
public interface ScheduledExecutorService extends ExecutorService { public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit); public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit); public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit); public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); }
- The
schedule()
methods create tasks with various delays and return a task object that can be used to cancel or check execution. - The
scheduleAtFixedRate()
andscheduleWithFixedDelay()
methods create and execute tasks that run periodically until cancelled. - Zero and negative delays (but not periods) are also allowed in schedule methods, and are treated as requests for immediate execution.
- All schedule methods accept relative delays and periods as arguments, not absolute times or dates.
- To schedule at a certain future date, we can use the api in following manner –
schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)
. - All methods return the ScheduledFuture object which is a delayed result-bearing action that can be cancelled.
2. ScheduledExecutorService Example
In this example, we will execute a simple task under various scenarios to better understand the usage of this interface.
class Task implements Callable<String> { private final String name; public Task(String name) { this.name = name; } @Override public String call() throws Exception { return "Task [" + name + "] executed on : " + LocalDateTime.now().toString(); } }
2.1. Execute a task at fixed delay
Java example to execute a task at fixed delay of 2 seconds using ScheduledExecutorService.
import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) throws InterruptedException { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); List<ScheduledFuture<String>> results = new ArrayList<ScheduledFuture<String>>(); for (int i = 1; i <= 5; i++) { Task task = new Task("Task-" + i); ScheduledFuture<String> result = executor.schedule(task, i*2, TimeUnit.SECONDS); results.add(result); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.DAYS); for(ScheduledFuture<String> result : results) { System.out.println(result.get()); } } catch (Exception e) { e.printStackTrace(); } } }
Program output.
Task [Task-1] executed on : 2019-05-23T14:01:24.497 Task [Task-2] executed on : 2019-05-23T14:01:26.410 Task [Task-3] executed on : 2019-05-23T14:01:28.411 Task [Task-4] executed on : 2019-05-23T14:01:30.410 Task [Task-5] executed on : 2019-05-23T14:01:32.411 Task [Task-1] is SUCCESS !! Task [Task-2] is SUCCESS !! Task [Task-3] is SUCCESS !! Task [Task-4] is SUCCESS !! Task [Task-5] is SUCCESS !!
2.2. Execute a task at a given time
If we want to execute a task at a given time, calculate the difference between that planned date and the current date and use the difference as the delay of the task.
import java.time.Duration; import java.time.LocalDateTime; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) throws InterruptedException, ExecutionException { ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); LocalDateTime now = LocalDateTime.now(); LocalDateTime afterOneMinute = now.plusMinutes(1); Duration duration = Duration.between(now, afterOneMinute); long delay = Math.abs(duration.toMillis()); System.out.println("Task scheduled at : "+ LocalDateTime.now()); ScheduledFuture<String> result = executor.schedule(new Task("Task-1"), delay, TimeUnit.MILLISECONDS); executor.shutdown(); executor.awaitTermination(1, TimeUnit.HOURS); System.out.println(result.get()); } }
Program output.
Task scheduled at : 2019-05-23T14:21:59.627 Task [Task-1] executed on : 2019-05-23T14:22:59.632 Task [Task-1] is SUCCESS !!
Drop me your questions related to ScheduledExecutorService in comments.
Happy Learning !!
References :
ScheduledExecutorService Java Doc
ScheduledThreadPoolExecutor Java Doc