.jpg)
开头还是那句话,懒人直接下源码,如果有疑问,请看帖子最后的总结。
懒人兄弟们,最近我的运气不好不坏,心情不好。
本范例演示quartz如何来处理大批量任务。
本例排程中预先安排了500个任务,因为线程池的大小为12,所以排程中最多只能12个线程同时运行。(译者注:任务是以线程的形式来运行,一次execute使用一个线程)。
我计算了一下,500项工作全部安排,前后任务启动时间间隔100豪秒,如果不考虑其他情况, 50秒内应当可以全部启动。但是前边我们说过,线程池只有12的大小。而且每次任务任务又休眠1分钟,最终只有60个任务得到执行。
线程池的大小可以在quartz.properties中修改。
任务的数量,预安排是500个,可以在运行本范例的时候,通过命令行参数重新指定。如何指定?我狂晕!无语问:苍天那,大地啊!看main()函数。
如果你要自己亲自动手实现本范例,注意必须的jar包如下:
commons-collections-3.1.jar
commons-logging.jar
log4j-1.2.11.jar
quartz-1.6.0.jar
配置文件2个,分别是:
log4j.xml
quartz.properties
1. log4j.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="default" class="org.apache.log4j.ConsoleAppender">
<param name="target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%p] %d{dd MMM hh:mm:ss.SSS aa} %t [%c]%n%m%n%n" />
</layout>
</appender>
<logger name="org.quartz">
<level value="debug" />
</logger>
<root>
<level value="debug" />
<appender-ref ref="default" />
</root>
</log4j:configuration>
2. quartz.properties
#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName = TestScheduler
org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 12
org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
#org.quartz.jobStore.useProperties = false
#org.quartz.jobStore.dataSource = myDS
#org.quartz.jobStore.tablePrefix = QRTZ_
#org.quartz.jobStore.isClustered = false
#============================================================================
# Configure Datasources
#============================================================================
#org.quartz.dataSource.myDS.driver = org.postgresql.Driver
#org.quartz.dataSource.myDS.URL = jdbc:postgresql://localhost/dev
#org.quartz.dataSource.myDS.user = jhouse
#org.quartz.dataSource.myDS.password =
#org.quartz.dataSource.myDS.maxConnections = 5
3. SimpleJob.java
package com.zbaccp.quartz.cl.example11;
import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 本任务没有任何特殊之处,核心在于LoadExample类
*
* @author 林艺
*/
public class SimpleJob implements Job {
private static Log _log = LogFactory.getLog(SimpleJob.class);
//任务体执行中的休眠时间
public static final String DELAY_TIME = "delay time";
public SimpleJob() {
}
/**
*
* 任务体<br/>
* 当与任务关联的触发器触发式时,由Scheduler调用
*
*/
public void execute(JobExecutionContext context)
throws JobExecutionException {
//本任务仅仅打印出任务名和开始、结束的时间
String jobName = context.getJobDetail().getFullName();
_log.info("#########开始任务: " + jobName + " 执行时间: " + new Date());
// 睡眠
long delayTime = context.getJobDetail().getJobDataMap().getLong(
DELAY_TIME);
try {
Thread.sleep(delayTime);
} catch (Exception e) {
}
_log.info("------###完成执行: " + jobName + " 时间: " + new Date());
}
}
4. LoadExample.java
package com.zbaccp.quartz.cl.example11;
import java.util.Date;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SchedulerMetaData;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;
/**
* 本范例演示quartz如何来处理大批量任务。<br/>本例排程中预先安排了500个任务,
* 由于线程池的大小为12,所以说排程中只有最多12个线程同时运行。(任务是以线程的形式来运行,一次任务使用一个线程)<br/>
* 线程池的大小可以在quartz.properties中修改。<br/>
* 任务的数量,预先安排是500个,可以在运行本范例的时候,通过命令行参数重新指定。
*
* @author 林艺
*/
public class LoadExample {
private int _numberOfJobs = 500;
public LoadExample(int inNumberOfJobs) {
_numberOfJobs = inNumberOfJobs;
}
public void run() throws Exception {
Log log = LogFactory.getLog(LoadExample.class);
// 1-- 排程实例化
SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();
log.info("------- 初始化完毕 -----------");
log.info("------- (没有预先安排任何任务,任务依赖于XML文件定义) --");
// 1.1 排程实例的id已经在quartz.properties中配置
String schedId = sched.getSchedulerInstanceId();
// 2-- 预安排500个job等待运行
for (int count = 1; count <= _numberOfJobs; count++) {
JobDetail job = new JobDetail("job" + count, "group1",
SimpleJob.class);
job.getJobDataMap().put(SimpleJob.DELAY_TIME, 60000L);
// 如果遭遇恢复或者失败情况,Scheduler是否重新任务
job.setRequestsRecovery(true);
SimpleTrigger trigger = new SimpleTrigger("trigger_" + count,
"group_1");
trigger.setStartTime(new Date(System.currentTimeMillis() + 10000L
+ (count * 100)));
Date dat = sched.scheduleJob(job, trigger);
System.out.println("=============" + count + " " + dat);
if (count % 25 == 0) {
log.info("...scheduled [" + count + "] jobs");
}
}
log.info("------- 排程开始启动 ----------------");
// 3-- 启动排程
sched.start();
log.info("------- 排程已经启动 -----------------");
log.info("------- 请等待5分钟... -----------");
// 4-- 等待,给排程任务运行时间
try {
Thread.sleep(300L * 1000L);
} catch (Exception e) {
}
// 5-- 关闭排程
log.info("------- 排程开始关闭 ---------------------");
sched.shutdown(true);
log.info("------- 排程已经关闭 -----------------");
SchedulerMetaData metaData = sched.getMetaData();
log.info("共执行任务 " + metaData.numJobsExecuted() + " 次。");
}
public static void main(String[] args) throws Exception {
// 可以通过命令行参数,改变预设任务的数量
// 不要问我命令行参数怎么设,我无言
int numberOfJobs = 500;
if (args.length == 1) {
numberOfJobs = Integer.parseInt(args[0]);
}
if (args.length > 1) {
System.out.println("Usage: java " + LoadExample.class.getName()
+ "[# of jobs]");
return;
}
LoadExample example = new LoadExample(numberOfJobs);
example.run();
}
}
5. 我们的结论
l 本次我们没有使用JobInitializationPlugin插件。任务定义唯一的来源是代码。
l 本范例任务没有全部执行的核心原因是线程池太小,每个任务的执行时间又太长。
l 最终只执行了60个任务,执行的任务编号没有特殊的含义。有大量的错失触发(misFire)产生。
l 记得西游记里镇元大仙的人参果树,一万年只结30颗。悟空教训八戒说:我们兄弟能吃到已经是莫大的缘分。所以因为职务低,体面地说法叫缘分未到,有些神仙连嗅过都没有。幸好观音的法力很大,医活了果树,否则很多神仙永远没有缘分了。
6. quartz.properties中配置的说明
org.quartz.threadPool.class
线程池的实现类
org.quartz.threadPool.threadCount
池中线程数量
org.quartz.threadPool.threadPriority
线程优先级
org.quartz.jobStore.misfireThreshold
触发器有丢失触发的情况,排程在运行时,触发器在超过下次触发预安排时间多少秒,才判为丢失触发。为了更少的丢失触发,可以把参数设置大一些。
关键字啊:misfireThreshold
文件下载:quartzOfficial11.rar