Run a Spring Boot Scheduled Task Only Once – Practical Code Guide
This article explains how to configure a Spring Boot scheduled task to execute just once, covering three approaches—specifying a start time with TaskScheduler, using @Scheduled with an initial delay, and creating a custom PeriodicTrigger—complete with runnable code examples.
In this article we learn how to control a scheduled task so that it runs only once in a Spring Boot 3.2.5 application. While @Scheduled is convenient for recurring jobs, sometimes a one‑time execution is required, such as initializing resources or performing a data migration.
1. Introduction
We will explore several methods to achieve a single‑run task, ranging from using @Scheduled with an initial delay to leveraging TaskScheduler and custom triggers.
2. Practical Cases
2.1 Specify a Start Time with TaskScheduler
The @Scheduled annotation lacks flexibility for one‑time tasks. By using Spring's TaskScheduler we can programmatically schedule a Runnable to run at a specific Instant :
public class TaskComponent {
private TaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
public void schedule(Runnable task, Instant startTime) {
taskScheduler.schedule(task, startTime);
}
}This method is ideal because all other TaskScheduler methods are intended for periodic execution.
Note: The example uses SimpleAsyncTaskScheduler . In Spring 6.1+ you can enable virtual threads:
SimpleAsyncTaskScheduler scheduler = new SimpleAsyncTaskScheduler();
scheduler.setVirtualThreads(true);A unit test can verify the one‑time execution:
@Test
public void testOnceTask() throws Exception {
CountDownLatch cdl = new CountDownLatch(1);
scheduler.schedule(() -> {
cdl.countDown();
// TODO: task action
}, Instant.now().plus(Duration.ofSeconds(1)));
cdl.await();
}2.2 Using @Scheduled with Initial Delay
Another option is to use the @Scheduled annotation with initialDelay while omitting fixedDelay or fixedRate:
@Component
public class TaskComponent {
@Scheduled(initialDelay = 3000)
public void task() {
// TODO: task action
}
}This runs the task once after a 3‑second delay and does not repeat.
2.3 Custom Trigger with PeriodicTrigger
For maximum control we can implement a custom trigger by extending PeriodicTrigger and overriding nextExecution() to return null after the first execution:
public class PackTrigger extends PeriodicTrigger {
public PackTrigger(Instant when) {
super(Duration.ofSeconds(1));
Duration difference = Duration.between(Instant.now(), when);
setInitialDelay(difference);
}
@Override
public Instant nextExecution(TriggerContext triggerContext) {
if (triggerContext.lastCompletion() == null) {
return super.nextExecution(triggerContext);
}
// Returning null stops further executions
return null;
}
}Using this trigger:
TaskScheduler taskScheduler = new SimpleAsyncTaskScheduler();
taskScheduler.schedule(() -> {
System.out.printf("%s, executing task%n", Thread.currentThread().getName());
}, new PackTrigger(Instant.now().plusSeconds(2)));This custom trigger provides the most flexible way to ensure a scheduled task runs only once.
Below are two illustrative images from the original article:
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
