Q:

Ensure that Spring Quartz job execution doesn't overlap

I have a Java program that executes from Spring Qquartz every 20 seconds.  Sometimes it takes just few seconds to execute, but as data gets bigger I'm sure it run for 20 seconds or more. 
How can I prevent Quartz from firing/triggering the job while one instance is still being executed?  Firing 2 jobs performing same operations on a database would not be so good.  Is there a way I can do some kind of synchronization? 

A:

Quartz 1
If you change your class to implement StatefulJob instead of Job, Quartz will take care of this for you.  From the StatefulJob javadoc:

stateful jobs are not allowed to
  execute concurrently, which means new
  triggers that occur before the
  completion of the execute(xx) method
  will be delayed. 

StatefulJob extends Job and does not add any new methods, so all you need to do to get the behaviour you want is change this:
public class YourJob implements org.quartz. Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

To this:
public class YourJob implements org.quartz. StatefulJob {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

Quartz 2
In version 2.0 of Quartz, StatefulJob is deprecated.  It is now recommended to use annotations instead, e.g.
@DisallowConcurrentExecution
public class YourJob implements org.quartz. Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

A:

If all you need to do is fire every 20 seconds, Quartz is serious overkill.  The java.util.concurrent. ScheduledExecutorService should be perfectly sufficient for that job. 
The ScheduledExecutorService also provides two semantics for scheduling. " fixed rate" will attempt to run your job every 20 seconds regardless of overlap, whereas "fixed delay" will attempt to leave 20 seconds between the end of the first job and the start of the next.  If you want to avoid overlap, then fixed-delay is safest. 

A:

Just in case anyone references this question, StatefulJob has been deprecated.   They now suggest you use annotations instead...
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

This will explain what those annotations mean...

The annotations cause behavior just as
  their names describe - multiple
  instances of the job will not be
  allowed to run concurrently (consider
  a case where a job has code in its
  execute() method that takes 34 seconds
  to run, but it is scheduled with a
  trigger that repeats every 30
  seconds), and will have its JobDataMap
  contents re-persisted in the
  scheduler's JobStore after each
  execution.  For the purposes of this
  example, only
  @PersistJobDataAfterExecution
  annotation is truly relevant, but it's
  always wise to use the
  @DisallowConcurrentExecution
  annotation with it, to prevent
  race-conditions on saved data.