Spring Boot中@Scheduled定时方法运行时如何通知其他RestController
Spring Boot 多定时任务状态感知实现方案
以下是适配不同部署场景的可落地方案:
方案1:单实例部署场景(内存状态共享)
该方案无需引入额外组件,性能最优,适合单体服务部署场景。
步骤1:定义线程安全的状态持有单例Bean
import org.springframework.stereotype.Component; import java.util.concurrent.atomic.AtomicBoolean; /** * 定时任务运行状态全局持有类,Spring单例模式保证多Bean共享同一份状态 */ @Component public class ScheduledTaskStatus { // 原子布尔类保证线程可见性、原子性,避免并发修改异常 private final AtomicBoolean methodARunningFlag = new AtomicBoolean(false); public boolean isMethodARunning() { return methodARunningFlag.get(); } public void setMethodARunning(boolean status) { methodARunningFlag.set(status); } }
步骤2:修改ControllerA的methodA逻辑,更新运行状态
@Controller public class ControllerA { private final ScheduledTaskStatus scheduledTaskStatus; // 构造注入状态持有Bean public ControllerA(ScheduledTaskStatus scheduledTaskStatus) { this.scheduledTaskStatus = scheduledTaskStatus; } @Scheduled(cron = "0 0/2 * * * *", zone = "GMT") public void methodA() { try { // 任务启动前更新状态为运行中 scheduledTaskStatus.setMethodARunning(true); // 原有业务逻辑 // do something } finally { // 任务结束(无论成功/异常)强制复位状态,避免永久标记为运行中 scheduledTaskStatus.setMethodARunning(false); } } }
步骤3:ControllerB中直接读取状态
@Controller public class ControllerB { private final ScheduledTaskStatus scheduledTaskStatus; public ControllerB(ScheduledTaskStatus scheduledTaskStatus) { this.scheduledTaskStatus = scheduledTaskStatus; } @Scheduled public void methodB() { if (scheduledTaskStatus.isMethodARunning()) { // 此时已感知到methodA正在运行,执行对应逻辑 } } }
方案2:分布式多实例部署场景
如果服务是集群部署,内存状态无法跨实例共享,可使用以下两种实现:
- Redis共享状态:methodA启动时往Redis写入带过期时间的标识key,任务结束删除key,methodB执行时查询该key是否存在即可判断运行状态,注意过期时间需略大于methodA的最大预计运行时长,避免实例宕机导致脏状态。
- Spring事件+消息队列:如果需要实时触发通知而非定时轮询状态,可在methodA启动/结束时发布事件,通过MQ广播到所有实例,各实例本地维护状态标识即可。
注意事项
- 不要使用普通的
boolean变量作为状态标识,多线程场景下会有可见性问题,导致状态读取不准 - 状态复位逻辑必须放在
finally代码块中,避免业务代码抛出异常导致状态永远为运行中
内容的提问来源于stack exchange,提问作者ErEcTuS
相关产品推荐
相关产品推荐

