You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot如何实现定时任务与接口方法的互斥执行?

解决方案

可以通过Java并发工具类结合Spring特性实现需求,核心思路是用锁控制两个方法的互斥,同时用原子变量过滤second的重复请求。

核心实现代码

在你的控制器/调度类中定义并发控制成员变量并修改方法逻辑:

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class YourController {
    // 控制first和second互斥的锁
    private final ReentrantLock dbOperationLock = new ReentrantLock();
    // 标记second是否正在执行,过滤重复请求
    private final AtomicBoolean isSecondProcessing = new AtomicBoolean(false);

    @Scheduled(cron = "0 * * * * *")
    public void first() {
        // 尝试获取锁,失败则直接跳过本次执行(不等待、不排队)
        if (!dbOperationLock.tryLock()) {
            return;
        }
        try {
            // 你的数据库操作逻辑
        } finally {
            // 必须在finally中释放锁,防止异常导致锁泄漏
            dbOperationLock.unlock();
        }
    }

    @RequestMapping(value = "/second", method = RequestMethod.POST)
    public void second() {
        // CAS操作:只有当前无second执行时,才标记为正在执行,否则直接返回
        if (!isSecondProcessing.compareAndSet(false, true)) {
            return;
        }
        try {
            // 阻塞等待锁释放(如果first正在运行,会等它执行完)
            dbOperationLock.lock();
            try {
                // 你的数据库操作逻辑
            } finally {
                dbOperationLock.unlock();
            }
        } finally {
            // 无论是否异常,都标记second执行完成
            isSecondProcessing.set(false);
        }
    }
}

逻辑说明

  • first()定时任务:
    使用tryLock()尝试获取锁,获取失败直接返回,完全符合"second执行期间阻止first运行,不等待不排队"的需求;获取成功则执行数据库操作,最后在finally中释放锁。

  • second()接口:

    1. 通过AtomicBoolean.compareAndSet做CAS校验,确保同一时间只有一个second请求被处理,重复请求直接忽略;
    2. 使用lock()阻塞等待锁,如果此时first正在运行,会等待first执行完释放锁后再执行自身逻辑;
    3. 执行完成后,在finally块中重置原子变量和释放锁,避免异常导致资源泄漏。

注意事项

  • 确保类是Spring单例(默认@RestController、@Component等注解均为单例),否则锁和原子变量会失去作用;
  • 锁的范围尽量缩小,只包裹数据库操作核心逻辑,减少锁持有时间以提升性能;
  • 若需要给前端反馈(如重复请求被忽略),可在return前添加响应逻辑,比如返回ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body("操作正在处理,请稍后再试")。

内容的提问来源于stack exchange,提问作者Wes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 23:06:22