Quartz实现固定执行次数

本文介绍如何使用Quartz框架实现固定次数的任务调度。通过StatefulJob记录执行次数,并利用TriggerListener监听执行过程,达到指定次数后自动停止。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Quartz实现固定执行次数 
虽然上一讲中说明,在实际应用中很少用到Quartz实现固定执行次数,但是我就是那个钻牛角尖的人.废话不多,代码如下: 

实现思路: 
1. 在上一讲中说明Quartz的JobDetail可以是无状态的,也可以是有状态的。Trigger无状态的,所以只能使用JobDetail有状态的子接口StatefulJob.Job代码如下: 
Java代码  收藏代码
  1. package test.quartz.spring;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import org.quartz.Job;  
  6. import org.quartz.JobDataMap;  
  7. import org.quartz.JobExecutionContext;  
  8. import org.quartz.JobExecutionException;  
  9. import org.quartz.StatefulJob;  
  10.   
  11. public class TJob implements StatefulJob {  
  12.   
  13.     /** 
  14.      * 不用挣扎了,Quartz都是无状态的,他不知道执行了几次。 
  15.      * 如果想要记录状态就需要持久化到数据库. 
  16.      */  
  17.     public void execute(JobExecutionContext cntxt) throws JobExecutionException {  
  18.            
  19.         JobDataMap jobDataMap = cntxt.getJobDetail().getJobDataMap();  
  20.         Integer count = (Integer) jobDataMap.get("count");  
  21.         if(count==null){  
  22.             count=0;  
  23.         }  
  24.         count++;  
  25.          System.out.println("杨春龙,太帅了");  
  26.          System.out.println("不是我说的");  
  27.          System.out.println( " Generating report -  "  
  28.                 +  count  
  29.                 +  "-"  
  30.                 +   new  Date());  
  31.          jobDataMap.put("count", count);  
  32.          cntxt.getJobDetail().setJobDataMap(jobDataMap);  
  33.            
  34.   
  35.     }  
  36.   
  37. }  

根据ApI描述,如果是有状态的Job,所有的Job都共享jobDataMap,所有把执行次数记录下来.虽然我记录了执行次数,但是因为Job是一个Thread,由ThreadPool来维持,那么如何监视Job的执行情况,在看源码中,发现有一个Listener,可以监听进程的执行,代码如下: 
Java代码  收藏代码
  1. package test.quartz.spring;  
  2.   
  3. import org.quartz.CronTrigger;  
  4. import org.quartz.JobExecutionContext;  
  5. import org.quartz.SchedulerException;  
  6. import org.quartz.Trigger;  
  7. import org.quartz.listeners.TriggerListenerSupport;  
  8.   
  9. public class TriggerListener extends TriggerListenerSupport {  
  10.       
  11.     private String name;    
  12.       
  13.     private Integer count;   
  14.     public void setName(String name)     
  15.     {     
  16.         this.name=name;     
  17.     }     
  18.       
  19.     public String getName() {  
  20.         // TODO Auto-generated method stub  
  21.         return this.name;  
  22.     }  
  23.       
  24.   
  25.     public Integer getCount() {  
  26.         return count;  
  27.     }  
  28.   
  29.     public void setCount(Integer count) {  
  30.         this.count = count;  
  31.     }  
  32.   
  33.     @Override  
  34.     public void triggerComplete(Trigger trigger, JobExecutionContext context,  
  35.             int triggerInstructionCode) {  
  36.         System.out.println("Trigger :"+trigger.getGroup()+"."+trigger.getName()+" completed with code:"+triggerInstructionCode);  
  37.         Integer current = (Integer) context.getJobDetail().getJobDataMap().get("count");  
  38.         System.out.println("调用次数:"+current);    
  39.         if(current == count){  
  40.             try {  
  41.                 context.getScheduler().shutdown();  
  42.             } catch (SchedulerException e) {  
  43.                 // TODO Auto-generated catch block  
  44.                 e.printStackTrace();  
  45.             }  
  46.         }  
  47.         super.triggerComplete(trigger, context, triggerInstructionCode);  
  48.     }  
  49.   
  50.       
  51.   
  52. }  

在Job的执行中设置执行次数,在监听器中得到执行次数,当执行次数到达count的时候退出执行. 
JobQuartz.xml配置如下 
Java代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">  
  3.   
  4. <beans>  
  5. <!--要调度的对象-->  
  6.   
  7.     <bean id="job" class="test.quartz.spring.TJob"></bean>  
  8.     <bean id="triggerListener" class="test.quartz.spring.TriggerListener">  
  9.         <property name="name">  
  10.             <value>triggerListener</value>  
  11.         </property>  
  12.         <property name="count">  
  13.             <value>3</value>  
  14.         </property>   
  15.     </bean>  
  16. <!-- 定义目标bean和bean中的方法 -->  
  17.     <bean id="jobtask" class="org.springframework.scheduling.quartz.JobDetailBean">  
  18.         <property name="jobClass">  
  19.             <value>test.quartz.spring.TJob</value>  
  20.         </property>  
  21.   
  22.     </bean>  
  23. <!-- 定义触发的时间 -->  
  24.     <bean id = "cron" class = "org.springframework.scheduling.quartz.CronTriggerBean">  
  25.         <!-- jobDetail中的name,group都已经设置 -->  
  26.         <property name="jobDetail">  
  27.             <ref bean="jobtask"/>  
  28.         </property>  
  29.         <property name="triggerListenerNames">    
  30.             <list>    
  31.                <value>triggerListener</value>    
  32.             </list>    
  33.         </property>     
  34.         <property name="cronExpression">  
  35.             <value>0/10 * * * * ?</value>  
  36.         </property>   
  37.     </bean>  
  38. <!-- 总管理 -->  
  39.     <bean autowire = "no" class = "org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  40.         <property name="triggers">  
  41.             <list>  
  42.                 <ref local ="cron"/>  
  43.             </list>  
  44.         </property>  
  45.         <!-- 添加监听器 -->  
  46.         <property name="triggerListeners">    
  47.             <list>    
  48.                 <ref bean="triggerListener"/>   
  49.             </list>    
  50.         </property>    
  51.           
  52.     </bean>  
  53.   
  54. </beans>  

在SchedulerFactoryBean中配置监听器列表,在CronTriggerBean配置监听器名称,这样这个监听器就可以监听这个Trigger了,当执行了3次后自动退出 
测试代码如下: 
Java代码  收藏代码
  1. package test.quartz.spring;  
  2.   
  3. import org.springframework.context.ApplicationContext;  
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  5.   
  6. public class TestSpring {  
  7.   
  8.     /** 
  9.      * @param args 
  10.      */  
  11.     public static void main(String[] args) {  
  12.         System.out.println("测试开始");  
  13.         ApplicationContext ctx = new ClassPathXmlApplicationContext("JobQuartz.xml");  
  14.         System.out.println("测试结束");  
  15.   
  16.     }  
  17.   
  18. }  

测试输出如下: 
测试开始 
Java代码  收藏代码
  1. 2010-09-27 09:33:39,640 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@3e86d0: display name [org.springframework.context.support.ClassPathXmlApplicationContext@3e86d0]; startup date [Mon Sep 27 09:33:39 CST 2010]; root of context hierarchy>  
  2. 2010-09-27 09:33:39,718 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [JobQuartz.xml]>  
  3. 2010-09-27 09:33:39,781 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@3e86d0]: org.springframework.beans.factory.support.DefaultListableBeanFactory@197a37c>  
  4. 2010-09-27 09:33:39,812 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@197a37c: defining beans [job,triggerListener,jobtask,cron,org.springframework.scheduling.quartz.SchedulerFactoryBean#0]; root of factory hierarchy>  
  5. 2010-09-27 09:33:39,953 INFO [org.quartz.core.SchedulerSignalerImpl] - <Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl>  
  6. 2010-09-27 09:33:39,953 INFO [org.quartz.core.QuartzScheduler] - <Quartz Scheduler v.1.8.3 created.>  
  7. 2010-09-27 09:33:39,953 INFO [org.quartz.simpl.RAMJobStore] - <RAMJobStore initialized.>  
  8. 2010-09-27 09:33:39,953 INFO [org.quartz.core.QuartzScheduler] - <Scheduler meta-data: Quartz Scheduler (v1.8.3'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' with instanceId 'NON_CLUSTERED'  
  9.   Scheduler class'org.quartz.core.QuartzScheduler' - running locally.  
  10.   NOT STARTED.  
  11.   Currently in standby mode.  
  12.   Number of jobs executed: 0  
  13.   Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.  
  14.   Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.  
  15. >  
  16. 2010-09-27 09:33:39,953 INFO [org.quartz.impl.StdSchedulerFactory] - <Quartz scheduler 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' initialized from an externally provided properties instance.>  
  17. 2010-09-27 09:33:39,953 INFO [org.quartz.impl.StdSchedulerFactory] - <Quartz scheduler version: 1.8.3>  
  18. 2010-09-27 09:33:39,953 INFO [org.quartz.core.QuartzScheduler] - <JobFactory set to: org.springframework.scheduling.quartz.AdaptableJobFactory@1b09468>  
  19. 2010-09-27 09:33:39,953 INFO [org.springframework.scheduling.quartz.SchedulerFactoryBean] - <Starting Quartz Scheduler now>  
  20. 2010-09-27 09:33:39,953 INFO [org.quartz.core.QuartzScheduler] - <Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED started.>  
  21. 测试结束  
  22. 杨春龙,太帅了  
  23. 不是我说的  
  24.  Generating report -  1-Mon Sep 27 09:33:40 CST 2010  
  25. Trigger :DEFAULT.cron completed with code:0  
  26. 调用次数:1  
  27. 杨春龙,太帅了  
  28. 不是我说的  
  29.  Generating report -  2-Mon Sep 27 09:33:50 CST 2010  
  30. Trigger :DEFAULT.cron completed with code:0  
  31. 调用次数:2  
  32. 杨春龙,太帅了  
  33. 不是我说的  
  34.  Generating report -  3-Mon Sep 27 09:34:00 CST 2010  
  35. Trigger :DEFAULT.cron completed with code:0  
  36. 调用次数:3  
  37. 2010-09-27 09:34:00,000 INFO [org.quartz.core.QuartzScheduler] - <Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED shutting down.>  
  38. 2010-09-27 09:34:00,000 INFO [org.quartz.core.QuartzScheduler] - <Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED paused.>  
  39. 2010-09-27 09:34:00,000 INFO [org.quartz.core.QuartzScheduler] - <Scheduler org.springframework.scheduling.quartz.SchedulerFactoryBean#0_$_NON_CLUSTERED shutdown complete.>  
### 解决Quartz调度器同一时间触发两次的问题 当遇到Quartz调度器在同一时间触发两次的情况时,可能的原因涉及配置不当、线程管理问题或是特定环境下的并发执行。为了有效解决问题并防止重复触发,可以采取以下措施: #### 配置唯一实例ID 确保每个Quartz Scheduler拥有唯一的`InstanceId`,这有助于避免集群环境中多个节点上的调度器误认为自己是独立运行而造成任务重叠。对于非集群模式下也应保持此设置的一致性和准确性[^1]。 ```xml <property name="scheduler.instanceId" value="AUTO"/> <!-- 或者指定一个固定的ID --> <property name="scheduler.instanceId" value="MY_UNIQUE_ID"/> ``` #### 调整线程池大小 适当调整用于执行作业的线程数量可以帮助减少因资源竞争而导致的任务重复启动现象。通常情况下,默认配置已经足够满足大多数应用场景的需求;但在高负载环境下,则需谨慎评估实际需求后再做相应修改[^2]。 ```properties org.quartz.threadPool.threadCount=5 ``` #### 设置防重入锁机制 通过实现Job接口中的`@DisallowConcurrentExecution`注解或继承自`StatefulJob`抽象类的方式,能够阻止同一个job实例被多次同时调用,从而达到预防重复触发的目的[^3]。 ```java import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; @DisallowConcurrentExecution public class MyUniqueJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // Your job logic here... } } ``` #### 使用结束时间和重复次数策略 合理利用`SimpleTrigger`提供的结束时间和最大重复次数参数组合,在某些场景下可有效控制任务不会无限制地频繁触发。需要注意的是,一旦指定了结束时间,则该设定会优先于任何其他关于循环计数的规定生效。 ```java // 创建简单触发器对象 SimpleTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("triggerName", "group1") .startNow() .endAt(endTime) // 设定终止日期/时刻 .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(60) .repeatForever()) .build(); ``` 以上方法综合运用后应该能较好地解决Quartz调度器在同一时间内意外触发两次的问题。当然具体实施还需结合项目实际情况灵活调整优化方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值