Backend Development 5 min read

Resolving Task Overlap and Scheduling Issues in Quartz with DisallowConcurrentExecution and Distributed Locks

This article explains why Quartz jobs can overlap when their execution time exceeds the trigger interval, demonstrates how to prevent concurrent execution with the @DisallowConcurrentExecution annotation, discusses distributed lock and idempotency solutions for clusters, and covers thread‑pool limits, exception handling, and a complete Java demo.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
Resolving Task Overlap and Scheduling Issues in Quartz with DisallowConcurrentExecution and Distributed Locks

1. In a single‑node Quartz scheduler, tasks may overlap and run concurrently if the job execution time is longer than the trigger interval; the article illustrates this with a job scheduled every 10 seconds that takes 20 seconds to complete.

Solution: add the @DisallowConcurrentExecution annotation to prevent overlapping executions on a single node. In a clustered environment, use a distributed lock or ensure job idempotency to avoid duplicate processing.

2. Using the @DisallowConcurrentExecution annotation can also cause inaccurate scheduling when a job runs longer than its interval, because the scheduler still attempts to fire the job at each interval regardless of the previous execution state.

3. The underlying cause lies in Quartz's in‑memory job store (RAMJobStore). When acquiring the next triggers, Quartz removes the trigger information; if the job is allowed to overlap, the trigger is re‑added for the next poll. The relevant methods are org.quartz.simpl.RAMJobStore#acquireNextTriggers , org.quartz.simpl.RAMJobStore#triggersFired , and org.quartz.simpl.RAMJobStore#triggeredJobComplete .

4. If the thread pool has no free threads, the scheduler thread blocks, preventing further scheduling. Quartz uses a fixed‑size SimpleThreadPool . When all threads are busy, the scheduler thread waits via org.quartz.core.QuartzSchedulerThread#run and org.quartz.simpl.SimpleThreadPool#blockForAvailableThreads .

5. To stop a job from being rescheduled, throw a JobExecutionException with an appropriate CompletedExecutionInstruction . This instruction determines whether Quartz should continue scheduling the job.

6. The article provides a complete Java example demonstrating the problem and the fix. The code creates a scheduler, defines a trigger with a cron expression (every 10 seconds), sets up a job that sleeps for 20 seconds, and shows how the scheduler behaves with and without the annotation.

package com.renzhikeji.demo;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import java.util.concurrent.TimeUnit;

/**
 * @author 认知科技技术团队
 */
public class QuartzDemo {
    public static void main(String[] args) throws SchedulerException, InterruptedException {
        // Create scheduler
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        // Create trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))
                .build();
        // Define job
        JobDetail job = JobBuilder.newJob(MyJob.class)
                .withIdentity("MyJob", "MyJob_Group")
                .usingJobData("author", "认知科技技术团队")
                .build();
        job.getJobDataMap().put("微信公众号", "认知科技技术团队");
        // Start scheduler
        scheduler.start();
        // Schedule job
        scheduler.scheduleJob(job, trigger);
        TimeUnit.HOURS.sleep(1);
        scheduler.shutdown(true);
    }

    public static class MyJob implements Job {
        @Override
        public void execute(JobExecutionContext context) {
            System.out.println("hello begin  " + Thread.currentThread().getName());
            try {
                TimeUnit.SECONDS.sleep(20);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("hello end  " + Thread.currentThread().getName());
        }
    }
}

The article also links to related Java pitfalls about ScheduledThreadPoolExecutor and provides additional images illustrating the described behaviors.

JavaConcurrencyDistributed LockQuartzJob SchedulingDisallowConcurrentExecution
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.