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

ShedLock如何通过锁名查询锁状态,解决长任务REST调用阻塞问题

问题根因说明

你遇到的锁提前释放问题,本质是@Async注解会将任务提交到线程池后立即返回,原调用线程的执行生命周期结束后就会触发锁释放逻辑,不会等待异步线程的任务执行完成。

适配方案

方案1:锁状态预检查实现非阻塞触发

这是最贴合你需求的实现方式:

  • 如果你使用的是Spring体系下的LockingTaskExecutor实现,可直接通过关联的LockRegistry获取锁实例,调用tryLock(0, TimeUnit.SECONDS)非阻塞预占锁,获取失败则直接返回"任务正在运行"
  • 预占锁成功后,新开异步线程执行业务逻辑,锁的释放操作绑定到异步线程的finally代码块,避免锁提前释放
  • 原REST调用线程提交完异步任务后直接返回触发结果

示例代码逻辑:

@Resource
private LockRegistry lockRegistry;
@Resource
private TaskExecutor asyncTaskExecutor;

public Result triggerTask(String lockKey, LockingTaskExecutor.TaskWithResult task) {
    // 非阻塞预检查锁状态
    Lock lock = lockRegistry.obtain(lockKey);
    if (!lock.tryLock()) {
        return Result.fail("当前任务已在执行,无需重复触发");
    }
    try {
        // 异步提交任务执行
        asyncTaskExecutor.execute(() -> {
            try {
                task.call();
                // 这里可自行持久化TaskResult供后续查询
            } finally {
                // 异步任务执行结束后释放锁
                lock.unlock();
            }
        });
        return Result.success("任务触发成功");
    } catch (Exception e) {
        // 异步提交失败时释放预占的锁,避免死锁
        lock.unlock();
        throw new BusinessException("任务触发失败", e);
    }
}

如果你的LockingTaskExecutor未暴露锁操作接口,可自行维护一个ConcurrentHashMap<String, AtomicBoolean>来记录锁的运行状态,状态更新操作要和锁的获取、释放逻辑保持原子性,避免状态不一致。

方案2:改造executeWithLock支持异步模式

无需依赖@Async注解,直接修改锁执行器的逻辑:

  • 给executeWithLock方法新增async布尔类型入参
  • 当async为true时,获取锁成功后将任务提交到独立的异步线程池执行,锁的释放逻辑绑定到异步任务的结束节点
  • 原调用线程提交完任务后直接返回任务唯一标识,可通过该标识后续查询任务执行状态

方案3:引入分布式任务调度组件(可选)

如果你的场景需要支持任务状态持久化、重试、失败告警等扩展能力,可引入xxl-job、Quartz等任务调度组件:

  • 给任务配置唯一幂等键,调度组件天然保证同一幂等键的任务同时仅存在一个运行实例
  • REST接口仅负责提交任务调度请求,无需等待执行结果,完全避免阻塞问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 23:54:03