Java 动态添加 `Scheduled` 定时任务
🏆本文收录于「滚雪球学SpringBoot」专栏,专业攻坚指数级提升持续更新中,up!up!up!!欢迎点赞&&收藏&&订阅。
@TOC
✨ 前言
在 Java 应用中,定时任务是一个非常常见的需求。Spring 提供了 @Scheduled
注解用于配置静态的定时任务,但某些场景下,我们需要动态地添加或移除定时任务,例如基于用户的配置、动态时间间隔调整等。本文将深入解析如何在 Spring 项目中动态添加 Scheduled
定时任务,并通过代码示例帮助你快速掌握。
📌 定时任务的基础:@Scheduled
在 Spring 中,@Scheduled
注解用于定义定时任务。它支持多种触发方式:
fixedRate
:固定频率触发。fixedDelay
:固定延迟触发。cron
:基于 Cron 表达式触发。
示例:静态定时任务
@Component
public class StaticScheduledTask {
@Scheduled(fixedRate = 5000) // 每 5 秒触发一次
public void runTask() {
System.out.println("Executing static scheduled task...");
}
}
虽然 @Scheduled
很方便,但它是静态的,无法在运行时动态添加或移除任务。因此,接下来我们介绍如何动态添加定时任务。
📌 动态添加定时任务的实现
Spring 的 TaskScheduler
接口提供了动态管理定时任务的能力。通过实现 TaskScheduler
,我们可以在运行时添加、移除和管理任务。
1. 使用 ThreadPoolTaskScheduler
动态管理定时任务
1.1 配置 TaskScheduler
Spring 提供了 ThreadPoolTaskScheduler
,这是一个线程池定时任务调度器。
配置类:
@Configuration
public class TaskSchedulerConfig {
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10); // 设置线程池大小
scheduler.setThreadNamePrefix("DynamicTask-");
return scheduler;
}
}
1.2 动态添加定时任务
通过 TaskScheduler
提供的方法,可以在运行时动态添加定时任务。
示例代码:
@Service
public class DynamicTaskService {
@Autowired
private TaskScheduler taskScheduler;
private ScheduledFuture<?> scheduledTask;
// 动态添加定时任务
public void addTask(Runnable task, long interval) {
if (scheduledTask != null) {
scheduledTask.cancel(true); // 如果已有任务,先取消
}
scheduledTask = taskScheduler.scheduleAtFixedRate(task, interval); // 添加新任务
}
// 动态移除定时任务
public void removeTask() {
if (scheduledTask != null) {
scheduledTask.cancel(true);
scheduledTask = null;
}
}
}
调用示例:
@RestController
@RequestMapping("/tasks")
public class TaskController {
@Autowired
private DynamicTaskService taskService;
@PostMapping("/start")
public String startTask(@RequestParam long interval) {
taskService.addTask(() -> System.out.println("Executing dynamic task..."), interval);
return "Task started with interval: " + interval + "ms";
}
@PostMapping("/stop")
public String stopTask() {
taskService.removeTask();
return "Task stopped.";
}
}
📌 基于 Cron 表达式的动态任务
除了固定间隔的定时任务,还可以基于 Cron 表达式 添加动态任务。
2.1 动态添加 Cron 表达式任务
Spring 的 CronTrigger
可以帮助我们动态创建基于 Cron 表达式的任务。
示例代码:
@Service
public class CronTaskService {
@Autowired
private TaskScheduler taskScheduler;
private ScheduledFuture<?> cronTask;
// 动态添加 Cron 表达式任务
public void addCronTask(Runnable task, String cronExpression) {
if (cronTask != null) {
cronTask.cancel(true); // 如果已有任务,先取消
}
CronTrigger cronTrigger = new CronTrigger(cronExpression); // 创建 CronTrigger
cronTask = taskScheduler.schedule(task, cronTrigger); // 添加任务
}
// 移除 Cron 表达式任务
public void removeCronTask() {
if (cronTask != null) {
cronTask.cancel(true);
cronTask = null;
}
}
}
2.2 调用示例
Controller 示例:
@RestController
@RequestMapping("/cron-tasks")
public class CronTaskController {
@Autowired
private CronTaskService cronTaskService;
@PostMapping("/start")
public String startCronTask(@RequestParam String cronExpression) {
cronTaskService.addCronTask(() -> System.out.println("Executing dynamic cron task..."), cronExpression);
return "Cron task started with expression: " + cronExpression;
}
@PostMapping("/stop")
public String stopCronTask() {
cronTaskService.removeCronTask();
return "Cron task stopped.";
}
}
启动示例:
- 请求:
POST /cron-tasks/start
- 参数:
cronExpression = "0/5 * * * * *"
(每 5 秒执行一次)
停止示例:
- 请求:
POST /cron-tasks/stop
📌 多任务的动态管理
在实际场景中,我们可能需要动态管理多个定时任务。这可以通过维护一个任务列表来实现。
3.1 多任务管理示例
Service 实现:
@Service
public class MultiTaskService {
@Autowired
private TaskScheduler taskScheduler;
private Map<String, ScheduledFuture<?>> tasks = new ConcurrentHashMap<>();
// 添加任务
public void addTask(String taskId, Runnable task, String cronExpression) {
if (tasks.containsKey(taskId)) {
tasks.get(taskId).cancel(true); // 如果任务已存在,先取消
}
CronTrigger cronTrigger = new CronTrigger(cronExpression);
ScheduledFuture<?> future = taskScheduler.schedule(task, cronTrigger);
tasks.put(taskId, future);
}
// 移除任务
public void removeTask(String taskId) {
if (tasks.containsKey(taskId)) {
tasks.get(taskId).cancel(true);
tasks.remove(taskId);
}
}
// 查看任务
public Set<String> listTasks() {
return tasks.keySet();
}
}
Controller 示例:
@RestController
@RequestMapping("/multi-tasks")
public class MultiTaskController {
@Autowired
private MultiTaskService multiTaskService;
@PostMapping("/add")
public String addTask(@RequestParam String taskId, @RequestParam String cronExpression) {
multiTaskService.addTask(taskId, () -> System.out.println("Task " + taskId + " is running..."), cronExpression);
return "Task added with ID: " + taskId;
}
@PostMapping("/remove")
public String removeTask(@RequestParam String taskId) {
multiTaskService.removeTask(taskId);
return "Task removed with ID: " + taskId;
}
@GetMapping("/list")
public Set<String> listTasks() {
return multiTaskService.listTasks();
}
}
📌 动态定时任务的注意事项
-
线程池管理:
- 确保线程池的大小足够,避免任务因线程耗尽而无法执行。
- 使用
ThreadPoolTaskScheduler
配置合理的线程池。
-
任务冲突:
- 在动态添加任务时,应避免任务 ID 冲突,建议使用唯一标识符。
-
Cron 表达式校验:
- 添加任务前,校验 Cron 表达式是否合法。
-
任务清理:
- 在移除任务时,一定要调用
cancel(true)
以释放资源。
- 在移除任务时,一定要调用
🔮 未来展望
-
支持动态优先级:
- 动态调整任务的优先级,保证高优任务优先执行。
-
任务状态监控:
- 集成监控工具(如 Prometheus、Grafana)实时查看任务执行状态。
-
持久化任务配置:
- 将动态任务配置存储到数据库中,支持重启后自动加载。
✨ 总结
通过 Spring 提供的 TaskScheduler
,我们可以非常方便地动态添加和管理定时任务,从而满足动态化、多任务管理的业务需求。在实际开发中,通过结合 Cron 表达式、多任务管理等技术,可以实现更加灵活的调度系统。
希望本文能帮助你更好地理解和实践动态定时任务的实现。如果你有更多问题或建议,欢迎交流!😊
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
✨️ Who am I?
我是bug菌,CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云2023年度十佳博主,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-
- 点赞
- 收藏
- 关注作者
评论(0)