How to run certain task every day at a particular time using ScheduledExecutorService?
Categories:
Scheduling Daily Tasks with ScheduledExecutorService in Java

Learn how to reliably execute recurring tasks at specific times each day using Java's ScheduledExecutorService
, ensuring your background processes run like clockwork.
In many applications, there's a need to perform certain operations at a fixed time every day. This could range from generating daily reports, cleaning up temporary files, sending out daily notifications, or performing database backups. While java.util.Timer
and TimerTask
can be used for basic scheduling, the java.util.concurrent.ScheduledExecutorService
offers a more robust, flexible, and powerful solution, especially in multi-threaded environments.
Understanding ScheduledExecutorService
ScheduledExecutorService
is an interface that combines the features of ExecutorService
(for managing threads and executing tasks) with the ability to schedule tasks to run after a delay or periodically. It's part of Java's Concurrency Utilities, designed for high-performance and reliable concurrent programming. Unlike Timer
, which uses a single background thread, ScheduledExecutorService
can be configured with a thread pool, making it more resilient to long-running tasks and exceptions.
flowchart TD A[Application Start] --> B{Initialize ScheduledExecutorService} B --> C[Create Runnable Task] C --> D{Calculate Initial Delay} D --> E[Schedule Task with Fixed Delay/Rate] E --> F[Task Execution Loop] F --> G{Perform Daily Operation} G --> F F --> H[Application Shutdown] --> I[Shutdown ExecutorService]
Workflow for scheduling a daily task using ScheduledExecutorService.
Calculating the Initial Delay
The key to running a task at a specific time each day, rather than just every 24 hours from application start, lies in calculating the initial delay until the first desired execution time. Subsequent executions can then be scheduled with a fixed period (e.g., 24 hours). This calculation involves determining the time difference between the current moment and the next occurrence of the target time.
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DailyTaskScheduler {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private final LocalTime targetTime;
public DailyTaskScheduler(LocalTime targetTime) {
this.targetTime = targetTime;
}
public void startScheduling(Runnable task) {
long initialDelay = calculateInitialDelay();
long period = TimeUnit.DAYS.toSeconds(1); // 24 hours in seconds
System.out.println("Scheduling task to run daily at " + targetTime + ".");
System.out.println("Initial delay: " + initialDelay + " seconds.");
scheduler.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS);
}
private long calculateInitialDelay() {
LocalDateTime now = LocalDateTime.now();
LocalDateTime nextExecutionTime = now.with(targetTime);
// If target time has already passed today, schedule for tomorrow
if (now.isAfter(nextExecutionTime)) {
nextExecutionTime = nextExecutionTime.plusDays(1);
}
Duration duration = Duration.between(now, nextExecutionTime);
return duration.getSeconds();
}
public void stopScheduling() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(10, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
System.out.println("Scheduler stopped.");
}
public static void main(String[] args) {
// Example: Run task every day at 10:30 AM
LocalTime dailyRunTime = LocalTime.of(10, 30, 0);
DailyTaskScheduler scheduler = new DailyTaskScheduler(dailyRunTime);
Runnable myDailyTask = () -> {
System.out.println("Daily task executed at: " + LocalDateTime.now());
// Add your actual daily logic here
// For example: generateReport(); cleanupFiles();
};
scheduler.startScheduling(myDailyTask);
// In a real application, you might keep the main thread alive
// or manage the scheduler's lifecycle differently.
// For demonstration, let's keep it running for a while.
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(2)); // Keep main thread alive for 2 minutes
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// scheduler.stopScheduling(); // Uncomment to stop the scheduler explicitly
}
}
Java code for scheduling a daily task at a specific time using ScheduledExecutorService
.
ScheduledExecutorService
, such as Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors())
or a custom ThreadPoolExecutor
to manage thread count and behavior more precisely.Key Components Explained
Let's break down the important parts of the provided solution:
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
This creates an executor service with a single thread. For tasks that are quick and don't block, one thread is often sufficient. If your daily task involves I/O or other blocking operations, or if you have multiple scheduled tasks, you might need a larger thread pool.LocalTime targetTime;
This stores the specific time of day (e.g., 10:30 AM) when the task should run.calculateInitialDelay()
This crucial method determines how many seconds fromnow
until thetargetTime
occurs next. It handles cases where thetargetTime
has already passed for the current day by scheduling it for the next day.scheduler.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.SECONDS);
This is the core scheduling method:task
: TheRunnable
(orCallable
) to be executed.initialDelay
: The time to wait before the first execution.period
: The time between successive executions. Here, it's set to 24 hours.TimeUnit.SECONDS
: The unit forinitialDelay
andperiod
.
scheduleAtFixedRate
is suitable when you want the task to run at a fixed interval, regardless of how long the task itself takes. If a task takes longer than the period, subsequent tasks will be delayed but will try to catch up. For tasks where you want a fixed delay between the end of one execution and the start of the next, usescheduleWithFixedDelay
instead.
ScheduledExecutorService
when your application exits to prevent resource leaks and ensure all threads are terminated gracefully. The stopScheduling()
method demonstrates a proper shutdown sequence.Alternative: Using Cron-like Schedulers
While ScheduledExecutorService
is powerful, for more complex scheduling requirements (e.g., "every Monday at 9 AM and every Friday at 5 PM," or "on the last day of the month"), external libraries or frameworks might be more suitable. Libraries like Quartz Scheduler or Spring's @Scheduled
annotation (which often uses ScheduledExecutorService
internally but provides a cron-like syntax) offer more expressive scheduling capabilities.

Choosing the right scheduling tool based on complexity and environment.
For simple daily tasks at a specific time, ScheduledExecutorService
provides a lightweight and built-in solution without external dependencies, making it an excellent choice for many Java applications.