Master Spring Boot 3 Task Scheduling: Interfaces, Annotations, Cron & Virtual Threads
This article explains how to use Spring Boot 3's TaskScheduler API, @Scheduled annotations, cron expressions, macro shortcuts, reactive support, virtual threads, and custom scheduling configuration, providing code examples and configuration tips for reliable backend task execution.
1. TaskScheduler Interface
Spring provides a TaskScheduler SPI with methods for scheduling tasks. The core interface is:
<code>public interface TaskScheduler {
ScheduledFuture schedule(Runnable task, Trigger trigger);
ScheduledFuture scheduleAtFixedRate(Runnable task, Instant startTime, Duration period);
ScheduledFuture scheduleWithFixedDelay(Runnable task, Instant startTime, Duration delay);
}</code>In a Spring Boot application you can inject it directly:
<code>@Resource
private TaskScheduler taskScheduler;
@PostConstruct
public void initScheduler() {
this.taskScheduler.schedule(() -> {
System.out.println("执行任务");
}, new CronTrigger("*/2 * * * * *"));
}</code>The above uses a cron expression to run every 2 seconds. You can also schedule at a fixed rate:
<code>this.taskScheduler.scheduleAtFixedRate(() -> {
System.out.println("固定周期指定任务");
}, Duration.ofSeconds(2)); // every 2 s</code>By default Spring Boot creates a ThreadPoolTaskScheduler with a single thread, which may cause task queuing when multiple jobs overlap. You can enlarge the pool via configuration:
<code>spring:
task:
scheduling:
thread-name-prefix: pack-task
pool:
size: 2</code>The property spring.task.scheduling.pool.size defaults to 1 .
2. Annotation‑Based Scheduling
The most common way to define scheduled jobs is with @Scheduled annotations. Example of a fixed‑delay task:
<code>@Scheduled(fixedDelay = 2000)
public void fixedDelayTask() throws Exception {
System.err.printf("Current Time: %s, Current Thread: %s%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(1);
}</code>Even though the delay is set to 2 s, the actual interval becomes 3 s because the execution time (1 s) is added.
Using a cron expression:
<code>@Scheduled(cron = "*/3 * * * * *")
public void task1() {
// TODO
}</code>This runs every 3 seconds.
3. Reactive Support
Since Spring Framework 6.1, reactive methods can also be scheduled:
<code>@Scheduled(fixedRate = 2, timeUnit = TimeUnit.SECONDS)
public Flux<Integer> reactiveTask() {
return Flux.just(1, 2, 3).doOnNext(System.err::println);
}</code>The method prints 1, 2, 3 every 2 seconds.
4. Cron Expressions and Macros
A standard cron expression consists of six space‑separated fields. Spring supports macros for common schedules, e.g., @hourly instead of 0 0 * * * . The table below shows the macros:
Macro
Description
@yearly (or @annually)
once a year (0 0 0 1 1 *)
@monthly
once a month (0 0 0 1 * *)
@weekly
once a week (0 0 0 * * 0)
@daily (or @midnight)
once a day (0 0 0 * * *)
@hourly
once an hour (0 0 * * *)
Example using a macro:
<code>@Scheduled(cron = "@hourly")
public void task2() {
System.out.println("宏指令执行任务");
}</code>5. Virtual Thread Support
From Spring 6.1 (JDK 21) you can enable virtual threads for scheduled tasks:
<code>spring:
threads:
virtual:
enabled: true</code>Example:
<code>@Scheduled(cron = "*/3 * * * * *")
public void scheduler1() throws Exception {
System.err.printf("当前时间: %s, 当前线程: %s, 是否虚拟线程: %b%n",
new SimpleDateFormat("HH:mm:ss").format(new Date()),
Thread.currentThread().getName(),
Thread.currentThread().isVirtual());
}</code>When virtual threads are used, the traditional thread‑pool size configuration becomes irrelevant.
6. Custom Scheduling Configuration
Implement SchedulingConfigurer to provide a custom TaskScheduler bean:
<code>@Component
public class PackSchedulingConfigurer implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setThreadNamePrefix("my-task-");
taskScheduler.afterPropertiesSet();
taskRegistrar.setTaskScheduler(taskScheduler);
}
}</code>You can also register tasks programmatically:
<code>public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addCronTask(() -> {
System.out.println("动态注册调度任务...");
}, "*/2 * * * * *");
}</code>These snippets demonstrate how to tailor the scheduling infrastructure to specific needs.
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.