如何在两个Spring定时批处理任务间设置执行延迟?
实现两个定时任务的互斥执行
要让两个定时任务互相等待,确保同一时间只有一个任务在执行,核心是引入共享互斥锁,让两个任务竞争同一把锁,锁被占用时则阻塞等待,直到持有锁的任务执行完成释放锁。
方案1:使用ReentrantLock实现灵活互斥
首先创建一个共享锁组件:
@Component public class JobLock { // 公平锁模式:按请求顺序分配锁,避免任务饥饿;无需公平性可省略true参数 public final ReentrantLock lock = new ReentrantLock(true); }
修改两个定时任务,注入共享锁并在执行逻辑前后加锁/释放锁:
@Component public class Job1 { private final JobLock jobLock; public Job1(JobLock jobLock) { this.jobLock = jobLock; } @Scheduled(fixedRate = 20000) public void execute() { try { // 阻塞等待获取锁,直到前一个任务执行完成 jobLock.lock.lock(); // -------------------------- // 这里编写你的业务逻辑 System.out.println("Job1 开始执行"); Thread.sleep(5000); // 模拟业务耗时 System.out.println("Job1 执行完成"); // -------------------------- } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { // 必须在finally中释放锁,防止异常导致锁无法释放 jobLock.lock.unlock(); } } }
@Component public class Job2 { private final JobLock jobLock; public Job2(JobLock jobLock) { this.jobLock = jobLock; } @Scheduled(fixedRate = 20000) public void execute() { try { jobLock.lock.lock(); // -------------------------- // 这里编写你的业务逻辑 System.out.println("Job2 开始执行"); Thread.sleep(3000); // 模拟业务耗时 System.out.println("Job2 执行完成"); // -------------------------- } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { jobLock.lock.unlock(); } } }
方案2:使用synchronized同步块(简单场景)
如果不需要ReentrantLock的高级特性,也可以用共享对象作为锁,通过synchronized实现互斥:
创建共享锁对象:
@Component public class SharedLock { public final Object lock = new Object(); }
修改任务代码:
@Component public class Job1 { private final SharedLock sharedLock; public Job1(SharedLock sharedLock) { this.sharedLock = sharedLock; } @Scheduled(fixedRate = 20000) public void execute() { synchronized (sharedLock.lock) { // 业务逻辑 System.out.println("Job1 执行中"); Thread.sleep(5000); } } }
Job2的修改方式和Job1完全一致,只需注入同一个SharedLock对象即可。
注意事项
fixedRate是以上次任务开始时间为基准计算下一次执行时间,如果任务耗时超过20秒,下一次触发会立即等待锁释放;若希望以上次任务结束时间为基准,改用fixedDelay = 20000,即任务完成后再过20秒才触发下一次。- 若不想无限等待锁,可以使用
ReentrantLock的tryLock(long timeout, TimeUnit unit)方法设置等待超时,超时后可选择跳过本次执行。
内容的提问来源于stack exchange,提问作者Prakash kumar mallick
相关产品推荐
相关产品推荐

