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

寻求@DisallowConcurrentExecution的有效替代方案(StatefulJob已废弃)

替代@DisallowConcurrentExecution的可行方案

方案一:通过JobDetail构建器禁用并发执行

这是最贴合原注解功能的替代方式,无需修改Job类代码,只需在创建JobDetail时通过Quartz API显式配置禁用并发:

// 创建JobDetail时调用disallowConcurrentExecution()方法
JobDetail jobDetail = JobBuilder.newJob(AJob.class)
    .withIdentity("aJob", "group1")
    .disallowConcurrentExecution() // 效果等价于@DisallowConcurrentExecution注解
    .build();

配置后,Quartz会保证同一个JobDetail的任务实例不会并发执行,和原注解的行为完全一致,且不需要在Job类上添加任何注解。

方案二:自定义锁实现并发控制

如果需要更灵活的控制(比如跨节点的全局并发限制),可以在Job的execute方法内部实现锁机制:

单节点场景(本地锁)

使用Java的ReentrantLock实现本地锁,确保同一JVM内只有一个任务实例在执行:

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.ZonedDateTime;
import java.util.concurrent.locks.ReentrantLock;

public class AJob implements Job {
    private static final Logger logger = LoggerFactory.getLogger(AJob.class);
    // 类级别的锁,确保所有任务实例共享同一锁
    private static final ReentrantLock lock = new ReentrantLock();

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        if (!lock.tryLock()) {
            logger.info("任务正在执行中,本次触发跳过");
            return;
        }
        try {
            logger.info("Scheduler output: " + ZonedDateTime.now().toString());
            // 模拟任务执行耗时
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new JobExecutionException(e);
        } finally {
            lock.unlock();
        }
    }
}

集群场景(分布式锁)

如果Quartz部署在集群环境,需要用分布式锁(如Redis锁)保证全局唯一执行:

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.time.ZonedDateTime;
import java.util.UUID;

public class AJob implements Job {
    private static final Logger logger = LoggerFactory.getLogger(AJob.class);
    // 锁的唯一标识key
    private static final String LOCK_KEY = "quartz:aJob:lock";
    // 锁超时时间,避免任务异常导致锁无法释放
    private static final int LOCK_TIMEOUT = 60;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        Jedis jedis = null;
        String requestId = UUID.randomUUID().toString();
        try {
            jedis = new Jedis("localhost", 6379);
            // 尝试获取分布式锁
            String result = jedis.set(LOCK_KEY, requestId, "NX", "EX", LOCK_TIMEOUT);
            if ("OK".equals(result)) {
                logger.info("Scheduler output: " + ZonedDateTime.now().toString());
                // 模拟任务执行耗时
                Thread.sleep(5000);
            } else {
                logger.info("任务正在集群中执行,本次触发跳过");
            }
        } catch (Exception e) {
            throw new JobExecutionException(e);
        } finally {
            // 仅持有锁的请求可释放锁
            if (jedis != null && requestId.equals(jedis.get(LOCK_KEY))) {
                jedis.del(LOCK_KEY);
                jedis.close();
            }
        }
    }
}

注:分布式锁可根据实际使用的缓存中间件调整实现,比如用Redisson能简化锁的续期等逻辑,上述为基础示例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:58:31