中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

網(wǎng)站分站作用網(wǎng)站推廣的目的

網(wǎng)站分站作用,網(wǎng)站推廣的目的,做視頻添加字幕的網(wǎng)站,外貿(mào)網(wǎng)站建設(shè)及優(yōu)化ppt模塊概述 定時(shí)器在應(yīng)用廣泛,比如定時(shí)統(tǒng)計(jì)數(shù)據(jù)生成報(bào)表、每隔設(shè)定的時(shí)間提醒用戶等。Java.util包自帶的定時(shí)器Timer提供簡(jiǎn)單的定點(diǎn)執(zhí)行功能,而Quartz是一個(gè)第三方提供的定時(shí)器框架。 對(duì)比 Timer 優(yōu)點(diǎn): java.util包自帶的,Timer的任務(wù)…

概述

定時(shí)器在應(yīng)用廣泛,比如定時(shí)統(tǒng)計(jì)數(shù)據(jù)生成報(bào)表、每隔設(shè)定的時(shí)間提醒用戶等。Java.util包自帶的定時(shí)器Timer提供簡(jiǎn)單的定點(diǎn)執(zhí)行功能,而Quartz是一個(gè)第三方提供的定時(shí)器框架。

對(duì)比

  • Timer
    • 優(yōu)點(diǎn):
      • java.util包自帶的,Timer的任務(wù)是通過(guò)創(chuàng)建TimerTask子類進(jìn)行實(shí)現(xiàn),使用方便。
    • 缺點(diǎn):
      • 定時(shí)器沒(méi)有持久性機(jī)制。
      • 定時(shí)器不能靈活的調(diào)度(只能設(shè)置開(kāi)始時(shí)間和重復(fù)間隔,沒(méi)有基于日期,一天中的時(shí)間等)
      • 定時(shí)器不使用線程池(每個(gè)定時(shí)器一個(gè)線程)
      • 定時(shí)器沒(méi)有真正的管理方案,必須編寫自己的機(jī)制管理。
  • Quartz
    • 優(yōu)點(diǎn):
      • Quartz是一個(gè)作業(yè)調(diào)度庫(kù),可以與任何其他軟件系統(tǒng)集成,也可以和其他軟件系統(tǒng)一起使用。
      • Quartz非常靈活,可以靈活、準(zhǔn)確的控制日期節(jié)點(diǎn)以及執(zhí)行次數(shù)。
      • Quartz非常輕量級(jí),只需要很少的配置即可完成需求,“開(kāi)箱即用”。
    • 缺點(diǎn):
      • Quartz必須要新建一個(gè)class文件實(shí)現(xiàn)Job接口重寫execute方法定義任務(wù)。

使用方法

Timer

Timer的任務(wù)是通過(guò)創(chuàng)建TimerTask子類進(jìn)行實(shí)現(xiàn),定時(shí)器由類Timer提供常見(jiàn)功能如下:

  • schedule(TimerTask task, Date time):在time時(shí)間點(diǎn)執(zhí)行task任務(wù)一次。
  • schedule(TimerTask task, long delay):在延遲delay毫秒后執(zhí)行task任務(wù)一次。
  • schedule(TimerTask task, Date firstTime, long period):在firsttime時(shí)間點(diǎn)執(zhí)行task一次,之后定期period毫秒時(shí)間執(zhí)行task。時(shí)間如果為過(guò)去時(shí)間, 不會(huì)執(zhí)行過(guò)去沒(méi)有執(zhí)行的任務(wù), 但是會(huì)馬上執(zhí)行。
  • schedule(TimerTask task, long delay, long period):在延遲delay后執(zhí)行task一次,之后定期period毫秒時(shí)間執(zhí)行task。時(shí)間如果為過(guò)去時(shí)間, 不會(huì)執(zhí)行過(guò)去沒(méi)有執(zhí)行的任務(wù), 但是會(huì)馬上執(zhí)行。

所有delay和period都是long類型的延遲時(shí)間,單位為毫秒。

指定開(kāi)始時(shí)間

package 定時(shí)器;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;public class TimerDemo {public static void main(String[] args) {method();System.out.println("main執(zhí)行完成");}public static void method() {// 1、創(chuàng)建Timer對(duì)象用于定義定時(shí)器的任務(wù)及開(kāi)始時(shí)間、周期Timer timer = new Timer();// 2、創(chuàng)建匿名內(nèi)部類,定義任務(wù)TimerTask task = new TimerTask() {int count = 1;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "指定時(shí)間定時(shí)任務(wù)執(zhí)行中count=" + (count++));}};// 3.任務(wù)調(diào)度timer.schedule(task, new Date());}
}

運(yùn)行結(jié)果:

結(jié)果看出,main執(zhí)行完成后推出,而定時(shí)任務(wù)另起線程執(zhí)行等待。

指定開(kāi)始時(shí)間及執(zhí)行周期

開(kāi)始時(shí)間為當(dāng)前時(shí)間,每一秒執(zhí)行一次。

public class TimerDemo {public static void main(String[] args) {method();method2();System.out.println("main執(zhí)行完成");}public static void method() {// 1、創(chuàng)建Timer對(duì)象用于定義定時(shí)器的任務(wù)及開(kāi)始時(shí)間、周期Timer timer = new Timer();// 2、創(chuàng)建匿名內(nèi)部類,定義任務(wù)TimerTask task = new TimerTask() {int count = 1;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "指定時(shí)間定時(shí)任務(wù)執(zhí)行中count=" + (count++));}};// 3.任務(wù)調(diào)度timer.schedule(task, new Date());}public static void method2() {// 1.創(chuàng)建Timer對(duì)象用于定義定時(shí)器的任務(wù)及開(kāi)始時(shí)間、周期Timer timer = new Timer();// 創(chuàng)建匿名內(nèi)部類,定義任務(wù)TimerTask task = new TimerTask() {int count2 = 1;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "指定時(shí)間循環(huán)定時(shí)任務(wù)執(zhí)行中count2=" + (count2++));}};// 2.任務(wù)調(diào)度 毫秒值timer.schedule(task, new Date(), 1000);}
}

運(yùn)行結(jié)果:

另起線程執(zhí)行,每間隔一秒執(zhí)行一次。

延期執(zhí)行及執(zhí)行周期

延遲4秒后執(zhí)行,每秒執(zhí)行一次。

public class TimerDemo {public static void main(String[] args) {method();method2();method3();System.out.println("main執(zhí)行完成");}public static void method() {...}public static void method2() {...}public static void method3() {// 1.創(chuàng)建Timer對(duì)象用于定義定時(shí)器的任務(wù)及開(kāi)始時(shí)間、周期Timer timer = new Timer();// 創(chuàng)建匿名內(nèi)部類,定義任務(wù)TimerTask task = new TimerTask() {int count3 = 1;@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "延時(shí)循環(huán)定時(shí)任務(wù)執(zhí)行中count3=" + (count3++));}};// 2.任務(wù)調(diào)度timer.schedule(task, 4000, 1000);}
}

運(yùn)行結(jié)果:

另起線程執(zhí)行,延遲4秒后執(zhí)行,每間隔一秒執(zhí)行一次。

Quartz

Quartz執(zhí)行需要1、創(chuàng)建一個(gè)SchedulerFactory對(duì)象用于生產(chǎn)調(diào)度器-Scheduler對(duì)象;2、創(chuàng)建調(diào)度所需要的任務(wù) 任務(wù)-Job;3、指定開(kāi)始的時(shí)間和執(zhí)行周期 觸發(fā)器-Trigger。

需要jar包:quartz-*.jar、slf4j-api-*.jar

示例

package QuartzTest;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.JobBuilder.newJob;public class TestQuartz {public static void main(String[] args) throws Exception{//1、創(chuàng)建工廠對(duì)象,用于生產(chǎn)調(diào)度器Scheduler對(duì)象Scheduler scheduler = new StdSchedulerFactory().getScheduler();//2、創(chuàng)建任務(wù)(JobDetail),具體的任務(wù)需要自定義類實(shí)現(xiàn)Job接口JobDetail jobDetail = newJob(MailJob.class) //指定干活的類MailJob.withIdentity("mailjob1", "mailgroup") //定義任務(wù)名稱和分組.usingJobData("email", "admin@10086.com") //定義屬性.build();//3、定義觸發(fā)器Trigger,設(shè)置開(kāi)始的時(shí)間及周期Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") //定義名稱和所屬的租.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1) //每隔2秒執(zhí)行一次.withRepeatCount(10)) //總共執(zhí)行11次(第一次執(zhí)行不基數(shù)).startNow().build();//4、調(diào)度器指定要執(zhí)行的任務(wù)JobDetail及觸發(fā)器Triggerscheduler.scheduleJob(jobDetail, trigger);//5、啟動(dòng)scheduler.start();//6、等待15秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(15000);scheduler.shutdown(true);System.out.printf(Thread.currentThread().getName() + " main關(guān)閉");}
}

自定義任務(wù)類MailJob實(shí)現(xiàn)Job接口:

package 定時(shí)器;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.text.SimpleDateFormat;
import java.util.Date;public class MailJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {JobDetail detail = context.getJobDetail();String email = detail.getJobDataMap().getString("email");SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");String now = sdf.format(new Date());System.out.printf("["+Thread.currentThread().getName()+"]" + new Date() +" 給郵件地址 %s 發(fā)出了一封定時(shí)郵件, 當(dāng)前時(shí)間是: %s%n" ,email, now);}
}

運(yùn)行結(jié)果:

.withIdentity(“mailjob1”, “mailgroup”)用于分組。
withIdentity定義任務(wù)名稱mailjob1和組名mailgroup。比如一個(gè)系統(tǒng)有3個(gè)job 是備份數(shù)據(jù)庫(kù)的,有4個(gè)job 是發(fā)郵件的,那么對(duì)他們進(jìn)行分組,可以方便管理,類似于一次性停止所有發(fā)郵件的這樣的操作。

任務(wù)-JobDetail

調(diào)度所需要的任務(wù)-JobDetail。需要新建一個(gè)類實(shí)現(xiàn)Job接口重寫execute方法定義任務(wù)。
JobDetail:描述這個(gè)Job是做什么的。
JobDataMap: 給Job提供參數(shù)用的。通過(guò)JobDetail.getJobDataMap獲取

  • getString(String key):獲取參數(shù)值
  • put(String key, String value):設(shè)置參數(shù)值
public class TestQuartz {public static void main(String[] args) throws Exception{...//2、創(chuàng)建任務(wù)(JobDetail),具體的任務(wù)需要自定義類實(shí)現(xiàn)Job接口JobDetail jobDetail = newJob(MailJob.class) //指定干活的類MailJob.withIdentity("mailjob1", "mailgroup") //定義任務(wù)名稱和分組.usingJobData("email", "admin@10086.com") //定義屬性.build();//用JobDataMap 修改emailjobDetail.getJobDataMap().put("email", "admin@taobao.com");...}
}

輸出:

Job 并發(fā)

Quartz定時(shí)任務(wù)默認(rèn)都是并發(fā)執(zhí)行的,無(wú)論上一次任務(wù)是否結(jié)束或者完成,只要間隔時(shí)間到就會(huì)執(zhí)行下一次, 因?yàn)槿绻〞r(shí)任執(zhí)行太長(zhǎng),會(huì)長(zhǎng)時(shí)間占用資源,導(dǎo)致其它任務(wù)堵塞。

數(shù)據(jù)執(zhí)行任務(wù)DatabaseBackupJob:

package QuartzTest;
import org.quartz.*;
import java.util.Date;public class DatabaseBackupJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {JobDetail detail = context.getJobDetail();String database = detail.getJobDataMap().getString("database");System.out.printf("["+Thread.currentThread().getName()+"]" + new Date() +" 給數(shù)據(jù)庫(kù) %s 備份, 耗時(shí)10秒 %n" ,database);try {Thread.sleep(10000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}

TestQuartz:

public class TestQuartz {public static void main(String[] args) throws Exception{databaseCurrentJob();}private static void databaseCurrentJob() throws Exception {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(2).withRepeatCount(10)).build();//定義一個(gè)JobDetailJobDetail jobDetail = newJob(DatabaseBackupJob.class).withIdentity("backupjob", "databasegroup").usingJobData("database", "how2java").build();//調(diào)度加入這個(gè)jobscheduler.scheduleJob(jobDetail, trigger);//啟動(dòng)scheduler.start();//等待100秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(100000);scheduler.shutdown(true);}
}

運(yùn)行結(jié)果:

由結(jié)果看出,任務(wù)并沒(méi)有等一個(gè)任務(wù)執(zhí)行完成,再執(zhí)行下一個(gè)任務(wù)。而是等待2秒就執(zhí)行下一個(gè)任務(wù)。
但是有時(shí)候會(huì)做長(zhǎng)時(shí)間的任務(wù),比如上述數(shù)據(jù)庫(kù)備份,這個(gè)時(shí)候就希望上一次備份成功結(jié)束之后,才開(kāi)始下一次備份,即便是規(guī)定時(shí)間到了,也不能開(kāi)始,因?yàn)檫@樣很有可能造成數(shù)據(jù)庫(kù)被鎖死 (幾個(gè)線程同時(shí)備份數(shù)據(jù)庫(kù),引發(fā)無(wú)法預(yù)計(jì)的混亂)。

那怎么實(shí)現(xiàn)呢?給任務(wù)增加注解 @DisallowConcurrentExecution
數(shù)據(jù)執(zhí)行任務(wù)DatabaseBackupJob:

package QuartzTest;
import org.quartz.*;
import java.util.Date;@DisallowConcurrentExecution
public class DatabaseBackupJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {...}
}

執(zhí)行結(jié)果:

由結(jié)果看出,任務(wù)會(huì)等前一個(gè)任務(wù)執(zhí)行完成(執(zhí)行10秒),才會(huì)執(zhí)行。

Job 異常

任務(wù)里發(fā)生異常是很常見(jiàn)的。 異常處理辦法通常是兩種:

  • setUnscheduleAllTriggers:當(dāng)異常發(fā)生,那么就通知所有管理這個(gè) Job 的調(diào)度,停止運(yùn)行它。
  • setRefireImmediately:當(dāng)異常發(fā)生,修改一下參數(shù),馬上重新運(yùn)行。
    ExceptionJob1:
public class ExceptionJob1  implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {int i = 0;try {//故意發(fā)生異常System.out.println(100/i);} catch (Exception e) {System.out.println("["+Thread.currentThread().getName()+"]" + new Date() + " 發(fā)生了異常,取消這個(gè)Job 對(duì)應(yīng)的所有調(diào)度");JobExecutionException je =new JobExecutionException(e);je.setUnscheduleAllTriggers(true);throw je;}}
}

ExceptionJob2:

public class ExceptionJob2  implements Job {static int i = 0;public void execute(JobExecutionContext context) throws JobExecutionException {try {//故意發(fā)生異常System.out.println("["+Thread.currentThread().getName()+"]" + new Date() + " 運(yùn)算結(jié)果"+100/i);} catch (Exception e) {System.out.println("["+Thread.currentThread().getName()+"]" + new Date() + " 發(fā)生了異常,修改一下參數(shù),立即重新執(zhí)行");i = 1;JobExecutionException je =new JobExecutionException(e);je.setRefireImmediately(true);throw je;}}
}

TestQuartz:

public class TestQuartz {public static void main(String[] args) throws Exception{exceptionHandle1();//exceptionHandle2();}private static void exceptionHandle1() throws Exception {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(2).withRepeatCount(5)).build();//定義一個(gè)JobDetailJobDetail jobDetail = newJob(ExceptionJob1.class).withIdentity("exceptionJob1", "someJobGroup").build();//調(diào)度加入這個(gè)jobscheduler.scheduleJob(jobDetail, trigger);//啟動(dòng)scheduler.start();//等待20秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(10000);scheduler.shutdown(true);}private static void exceptionHandle2() throws Exception {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(2).withRepeatCount(5)).build();//定義一個(gè)JobDetailJobDetail jobDetail = newJob(ExceptionJob2.class).withIdentity("exceptionJob1", "someJobGroup").build();//調(diào)度加入這個(gè)jobscheduler.scheduleJob(jobDetail, trigger);//啟動(dòng)scheduler.start();//等待20秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(10000);scheduler.shutdown(true);}
}

運(yùn)行結(jié)果:

執(zhí)行exceptionHandle2():

public class TestQuartz {public static void main(String[] args) throws Exception{//exceptionHandle1();exceptionHandle2();}
}

運(yùn)行結(jié)果:

中斷 Job

在業(yè)務(wù)上,有時(shí)候需要中斷任務(wù),那么這個(gè)Job需要實(shí)現(xiàn) InterruptableJob 接口,才可以被中斷。
StoppableJob:

package QuartzTest;
import org.quartz.InterruptableJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.UnableToInterruptJobException;import java.util.Date;//必須實(shí)現(xiàn)InterruptableJob 而非 Job才能夠被中斷
public class StoppableJob implements InterruptableJob {private boolean stop = false;public void execute(JobExecutionContext context) throws JobExecutionException {while(true){if(stop)break;try {System.out.println("["+Thread.currentThread().getName()+"]" + new Date() +" 每隔1秒,進(jìn)行一次檢測(cè),看看是否停止");Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("["+Thread.currentThread().getName()+"]" + new Date() +" 持續(xù)工作中。。。");}}public void interrupt() throws UnableToInterruptJobException {System.out.println("["+Thread.currentThread().getName()+"]" + new Date() +" 被調(diào)度叫停");stop = true;}
}

TestQuartz :

public class TestQuartz {public static void main(String[] args) throws Exception{stop();}private static void stop() throws Exception {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();Trigger trigger = newTrigger().withIdentity("trigger1", "group1").startNow().build();//定義一個(gè)JobDetailJobDetail jobDetail = newJob(StoppableJob.class).withIdentity("exceptionJob1", "someJobGroup").build();//調(diào)度加入這個(gè)jobscheduler.scheduleJob(jobDetail, trigger);//啟動(dòng)scheduler.start();Thread.sleep(5000);System.out.println("過(guò)5秒,調(diào)度停止 job");//key 就相當(dāng)于這個(gè)Job的主鍵scheduler.interrupt(jobDetail.getKey());//等待20秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(10000);scheduler.shutdown(true);}}

運(yùn)行結(jié)果:

觸發(fā)器-Trigger

指定開(kāi)始的時(shí)間和執(zhí)行周期。Trigger 就是觸發(fā)器的意思,用來(lái)指定什么時(shí)間開(kāi)始觸發(fā),觸發(fā)多少次,每隔多久觸發(fā)一次。
常見(jiàn)觸發(fā)器 SimpleTrigger、CronTrigger。

SimpleTrigger

常見(jiàn)方法:

  • withIdentity(String name, String group):設(shè)置觸發(fā)器名稱、組名
  • startNow():立即執(zhí)行
  • startAt(Date triggerStartTime):指定時(shí)間點(diǎn)執(zhí)行
10秒后運(yùn)行

DateBuilder.futureDate():可以方便的獲取10秒后, 5分鐘后, 3個(gè)小時(shí)候,2個(gè)月后這樣的時(shí)間。
QuartzDemo:

public class QuartzDemo {public static void main(String[] args) throws SchedulerException {//1、創(chuàng)建工廠對(duì)象,用于生產(chǎn)調(diào)度器Scheduler對(duì)象Scheduler scheduler = new StdSchedulerFactory().getScheduler();Date startTime = DateBuilder.futureDate(10, DateBuilder.IntervalUnit.SECOND);//2、創(chuàng)建任務(wù)(JobDetail),具體的任務(wù)需要自定義類實(shí)現(xiàn)Job接口JobDetail jobDetail = JobBuilder.newJob(MailJob.class) //指定干活的類MailJob.withIdentity("mailjob1", "mailgroup") //定義任務(wù)名稱和分組.usingJobData("email", "admin@10086.com") //定義屬性.build();//3、定義觸發(fā)器Trigger,設(shè)置開(kāi)始的時(shí)間及周期SimpleTrigger trigger = (SimpleTrigger) newTrigger().withIdentity("trigger1", "group1").startAt(startTime).build();//4、調(diào)度器指定要執(zhí)行的任務(wù)JobDetail及觸發(fā)器TriggerDate ft = scheduler.scheduleJob(jobDetail, trigger);System.out.println("當(dāng)前時(shí)間是:" + new Date().toLocaleString());System.out.printf("%s 這個(gè)任務(wù)會(huì)在 %s 準(zhǔn)時(shí)開(kāi)始運(yùn)行,累計(jì)運(yùn)行%d次,間隔時(shí)間是%d毫秒%n", job.getKey(), ft.toLocaleString(), trigger.getRepeatCount()+1, trigger.getRepeatInterval());//5、啟動(dòng)scheduler.start();}
}

運(yùn)行結(jié)果:

累計(jì)n次,間隔n秒
  • withSchedule
    • withIntervalInSeconds(n) :每隔n秒執(zhí)行一次
    • withRepeatCount(n)) :總共執(zhí)行n+1次(第一次執(zhí)行不基數(shù))
    • repeatForever():無(wú)限重復(fù)

QuartzDemo:

...
/3、定義觸發(fā)器Trigger,設(shè)置開(kāi)始的時(shí)間及周期SimpleTrigger trigger = (SimpleTrigger) newTrigger().withIdentity("trigger1", "group1").startAt(startTime).withSchedule(simpleSchedule().withRepeatCount(3).withIntervalInSeconds(1)).build();

運(yùn)行結(jié)果:

CronTrigger

Cron 是Linux下的一個(gè)定時(shí)器,功能很強(qiáng)大,但是表達(dá)式更為復(fù)雜。CronTrigger 就是用Cron表達(dá)式來(lái)安排觸發(fā)時(shí)間和次數(shù)的。

Cron表達(dá)式見(jiàn)《Cron表達(dá)式》

每隔2秒執(zhí)行一次
...
//3、定義觸發(fā)器Trigger,設(shè)置開(kāi)始的時(shí)間及周期CronTrigger trigger = (CronTrigger) newTrigger().withIdentity("trigger1", "group1").withSchedule(cronSchedule("0/2 * * * * ?")).build();

運(yùn)行結(jié)果:

調(diào)度器-Scheduler

  • Date scheduleJob(JobDetail var1, Trigger var2):將任務(wù)和觸發(fā)器加入調(diào)度器
  • start():啟動(dòng)
  • shutdown():關(guān)閉

監(jiān)聽(tīng)器

Quartz的監(jiān)聽(tīng)器有Job監(jiān)聽(tīng)器、Trigger監(jiān)聽(tīng)器、Scheduler監(jiān)聽(tīng)器,對(duì)不同層面進(jìn)行監(jiān)控。實(shí)際業(yè)務(wù)用的較多的是Job監(jiān)聽(tīng)器,用于監(jiān)聽(tīng)器是否執(zhí)行了,其他的用的相對(duì)較少,本知識(shí)主要講解Job的。
監(jiān)聽(tīng)器功能需要?jiǎng)?chuàng)建實(shí)現(xiàn)了 JobListener 接口的監(jiān)聽(tīng)器類。
JobListener接口方法如下:

  • public String getName():返回JobListener名稱。對(duì)于注冊(cè)為全局的監(jiān)聽(tīng)器,getName()主要用于記錄日志,對(duì)于由特定Job引用的 JobListener,注冊(cè)在 JobDetail 上的監(jiān)聽(tīng)器名稱必須匹配從監(jiān)聽(tīng)器上getName()返回值。
  • public void jobToBeExecuted(JobExecutionContext jobExecutionContext):Scheduler在 JobDetail 將要被執(zhí)行時(shí)調(diào)用的方法。
  • public void jobExecutionVetoed(JobExecutionContext jobExecutionContext):Scheduler在 JobDetail即將被執(zhí)行,但又被 Triggeristener否決了調(diào)用的方法。
  • public void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e):Scheduler在 JobDetail 被執(zhí)行之后調(diào)用的方法。

郵件監(jiān)聽(tīng)器MailJobListener:

package 定時(shí)器;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;public class MailJobListener implements JobListener {@Overridepublic String getName() {return "listener of mail job";}@Overridepublic void jobToBeExecuted(JobExecutionContext jobExecutionContext) {System.out.println("準(zhǔn)備執(zhí)行:\t "+jobExecutionContext.getJobDetail().getKey());}@Overridepublic void jobExecutionVetoed(JobExecutionContext jobExecutionContext) {System.out.println("取消執(zhí)行:\t "+jobExecutionContext.getJobDetail().getKey());}@Overridepublic void jobWasExecuted(JobExecutionContext jobExecutionContext, JobExecutionException e) {System.out.println("執(zhí)行結(jié)束:\t "+jobExecutionContext.getJobDetail().getKey());System.out.println();}
}

運(yùn)行結(jié)果:

數(shù)據(jù)庫(kù)存儲(chǔ)

Quartz的觸發(fā)器、調(diào)度、任務(wù)等信息都是放在內(nèi)存中的。不能對(duì)執(zhí)行進(jìn)度進(jìn)行實(shí)時(shí)查看,而且一旦系統(tǒng)異常,信息就會(huì)丟失。
所以Quartz還提供了另一個(gè)方式,可以把這些信息存放在數(shù)據(jù)庫(kù)中,叫做 JobStoreTX。運(yùn)行狀態(tài)信息存放在數(shù)據(jù)庫(kù)中。

建表

DROP DATABASE IF EXISTS quartz;
CREATE DATABASE quartz DEFAULT CHARACTER SET utf8;
USE quartz;DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;CREATE TABLE QRTZ_JOB_DETAILS(SCHED_NAME VARCHAR(120) NOT NULL,JOB_NAME  VARCHAR(100) NOT NULL,JOB_GROUP VARCHAR(100) NOT NULL,DESCRIPTION VARCHAR(250) NULL,JOB_CLASS_NAME   VARCHAR(250) NOT NULL,IS_DURABLE VARCHAR(1) NOT NULL,IS_NONCONCURRENT VARCHAR(1) NOT NULL,IS_UPDATE_DATA VARCHAR(1) NOT NULL,REQUESTS_RECOVERY VARCHAR(1) NOT NULL,JOB_DATA BLOB NULL,PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);CREATE TABLE QRTZ_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(100) NOT NULL,TRIGGER_GROUP VARCHAR(100) NOT NULL,JOB_NAME  VARCHAR(100) NOT NULL,JOB_GROUP VARCHAR(100) NOT NULL,DESCRIPTION VARCHAR(250) NULL,NEXT_FIRE_TIME BIGINT(13) NULL,PREV_FIRE_TIME BIGINT(13) NULL,PRIORITY INTEGER NULL,TRIGGER_STATE VARCHAR(16) NOT NULL,TRIGGER_TYPE VARCHAR(8) NOT NULL,START_TIME BIGINT(13) NOT NULL,END_TIME BIGINT(13) NULL,CALENDAR_NAME VARCHAR(100) NULL,MISFIRE_INSTR SMALLINT(2) NULL,JOB_DATA BLOB NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);CREATE TABLE QRTZ_SIMPLE_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(100) NOT NULL,TRIGGER_GROUP VARCHAR(100) NOT NULL,REPEAT_COUNT BIGINT(7) NOT NULL,REPEAT_INTERVAL BIGINT(12) NOT NULL,TIMES_TRIGGERED BIGINT(10) NOT NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_CRON_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(100) NOT NULL,TRIGGER_GROUP VARCHAR(100) NOT NULL,CRON_EXPRESSION VARCHAR(100) NOT NULL,TIME_ZONE_ID VARCHAR(80),PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_SIMPROP_TRIGGERS(         SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(100) NOT NULL,TRIGGER_GROUP VARCHAR(100) NOT NULL,STR_PROP_1 VARCHAR(512) NULL,STR_PROP_2 VARCHAR(512) NULL,STR_PROP_3 VARCHAR(512) NULL,INT_PROP_1 INT NULL,INT_PROP_2 INT NULL,LONG_PROP_1 BIGINT NULL,LONG_PROP_2 BIGINT NULL,DEC_PROP_1 NUMERIC(13,4) NULL,DEC_PROP_2 NUMERIC(13,4) NULL,BOOL_PROP_1 VARCHAR(1) NULL,BOOL_PROP_2 VARCHAR(1) NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_BLOB_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(100) NOT NULL,TRIGGER_GROUP VARCHAR(100) NOT NULL,BLOB_DATA BLOB NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_CALENDARS(SCHED_NAME VARCHAR(120) NOT NULL,CALENDAR_NAME  VARCHAR(100) NOT NULL,CALENDAR BLOB NOT NULL,PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_GROUP  VARCHAR(100) NOT NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_FIRED_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,ENTRY_ID VARCHAR(95) NOT NULL,TRIGGER_NAME VARCHAR(100) NOT NULL,TRIGGER_GROUP VARCHAR(100) NOT NULL,INSTANCE_NAME VARCHAR(100) NOT NULL,FIRED_TIME BIGINT(13) NOT NULL,SCHED_TIME BIGINT(13) NOT NULL,PRIORITY INTEGER NOT NULL,STATE VARCHAR(16) NOT NULL,JOB_NAME VARCHAR(100) NULL,JOB_GROUP VARCHAR(100) NULL,IS_NONCONCURRENT VARCHAR(1) NULL,REQUESTS_RECOVERY VARCHAR(1) NULL,PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);CREATE TABLE QRTZ_SCHEDULER_STATE(SCHED_NAME VARCHAR(120) NOT NULL,INSTANCE_NAME VARCHAR(100) NOT NULL,LAST_CHECKIN_TIME BIGINT(13) NOT NULL,CHECKIN_INTERVAL BIGINT(13) NOT NULL,PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);CREATE TABLE QRTZ_LOCKS(SCHED_NAME VARCHAR(120) NOT NULL,LOCK_NAME  VARCHAR(40) NOT NULL,PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);commit;

配置文件

Quartz默認(rèn)加載工程目錄下的quartz.properties,如果工程目錄下沒(méi)有,就會(huì)去加載quartz.jar包下面的quartz.properties文件。
故,在src下新建 quartz.properties 配置文件,里面指定使用 JobStoreTX 方式管理任務(wù)。

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.scheduler.instanceName = MyScheduler
org.quartz.threadPool.threadCount = 3
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = mysqlDatabaseorg.quartz.dataSource.mysqlDatabase.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.mysqlDatabase.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8
org.quartz.dataSource.mysqlDatabase.user = root
org.quartz.dataSource.mysqlDatabase.password = admin
org.quartz.dataSource.mysqlDatabase.maxConnections = 5

MailJob

和以前的一樣,沒(méi)什么變化。

package 定時(shí)器;
import org.quartz.*;
import java.text.SimpleDateFormat;
import java.util.Date;@DisallowConcurrentExecution
public class MailJob implements Job {public void execute(JobExecutionContext context) throws JobExecutionException {JobDetail detail = context.getJobDetail();String email = detail.getJobDataMap().getString("email");SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");String now = sdf.format(new Date());System.out.printf("["+Thread.currentThread().getName()+"]" + new Date() +" 給郵件地址 %s 發(fā)出了一封定時(shí)郵件, 當(dāng)前時(shí)間是: %s(%s) %n" ,email, now,context.isRecovering());}
}

TestQuartz

新增加了一個(gè)resumeJobFromDatabase 方法,當(dāng)使用原來(lái)的方式增加任務(wù)報(bào)異常的時(shí)候,就直接從數(shù)據(jù)庫(kù)重跑任務(wù)。

package 定時(shí)器;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import static org.quartz.TriggerBuilder.newTrigger;public class QuartzDemo {public static void main(String[] args) throws Exception {try {assginNewJob();} catch (ObjectAlreadyExistsException e) {System.err.println("發(fā)現(xiàn)任務(wù)已經(jīng)在數(shù)據(jù)庫(kù)存在了,直接從數(shù)據(jù)庫(kù)里運(yùn)行:"+ e.getMessage());// TODO Auto-generated catch blockresumeJobFromDatabase();}}private static void resumeJobFromDatabase() throws Exception {Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();scheduler.start();// 等待200秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(200000);scheduler.shutdown(true);}private static void assginNewJob() throws SchedulerException, InterruptedException {// 創(chuàng)建調(diào)度器Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定義一個(gè)觸發(fā)器Trigger trigger = newTrigger().withIdentity("trigger1", "group1") // 定義名稱和所屬的租.startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(15) // 每隔15秒執(zhí)行一次.withRepeatCount(10)) // 總共執(zhí)行11次(第一次執(zhí)行不基數(shù)).build();// 定義一個(gè)JobDetailJobDetail job = JobBuilder.newJob(MailJob.class) // 指定干活的類MailJob.withIdentity("mailjob1", "mailgroup") // 定義任務(wù)名稱和分組.usingJobData("email", "admin@10086.com") // 定義屬性.build();// 調(diào)度加入這個(gè)jobscheduler.scheduleJob(job, trigger);// 啟動(dòng)scheduler.start();// 等待20秒,讓前面的任務(wù)都執(zhí)行完了之后,再關(guān)閉調(diào)度器Thread.sleep(20000);scheduler.shutdown(true);}
}

第一次運(yùn)行:

QRTZ_SIMPLE_TRIGGERS:

QRTZ_TRIGGERS:

QRTZ_JOB_DETAILS:

第二次運(yùn)行:

注意:如果任務(wù)執(zhí)行完成,上述數(shù)據(jù)庫(kù)表數(shù)據(jù)均被清空。如果在執(zhí)行期間,查看數(shù)據(jù)庫(kù)表,表QRTZ_TRIGGERS、QRTZ_JOB_DETAILS數(shù)據(jù)不變,表QRTZ_SIMPLE_TRIGGERS會(huì)實(shí)時(shí)記錄執(zhí)行次數(shù):

字段REPEAT_COUNT記錄還需要執(zhí)行的總次數(shù),字段TIMES_TRIGGERED記錄執(zhí)行過(guò)的次數(shù)。

Quartz集群

所謂的Quartz集群,是指在基于數(shù)據(jù)庫(kù)存儲(chǔ)Quartz調(diào)度信息的基礎(chǔ)上,有多個(gè)一模一樣的 Quartz 應(yīng)用在運(yùn)行。
當(dāng)某一個(gè)Quartz應(yīng)用重啟或者發(fā)生問(wèn)題的時(shí)候,其他的Quartz應(yīng)用會(huì)借助數(shù)據(jù)庫(kù)這個(gè)橋梁探知到它不行了,從而接手把該進(jìn)行的Job調(diào)度工作進(jìn)行下去。
以這種方式保證任務(wù)調(diào)度的高可用性,即在發(fā)生異常重啟等情況下,調(diào)度信息依然連貫性地進(jìn)行下去,就好像Quartz應(yīng)用從來(lái)沒(méi)有中斷過(guò)似的。

quartz.properties

quartz.properties 在原來(lái)的基礎(chǔ)上,增加3行:

org.quartz.jobStore.isClustered = true
org.quartz.scheduler.instanceId = AUTO
org.quartz.jobStore.clusterCheckinInterval = 1000...
  • org.quartz.jobStore.isClustered = true:開(kāi)啟集群
  • org.quartz.scheduler.instanceId = AUTO:要進(jìn)行集群,多個(gè)應(yīng)用調(diào)度id instanceId 必須不一樣,這里使用AUTO,就會(huì)自動(dòng)分配不同的ID。 目測(cè)是本機(jī)機(jī)器名稱加上時(shí)間戳
  • org.quartz.jobStore.clusterCheckinInterval = 1000:每個(gè)一秒鐘去數(shù)據(jù)庫(kù)檢查一下,在其他應(yīng)用掛掉之后及時(shí)補(bǔ)上

注:要進(jìn)行集群,多個(gè)應(yīng)用調(diào)度名稱 instanceName 應(yīng)該是一樣的。

TestQuartz

TestQuartz 不需要做改動(dòng),本例增加一些輸出信息。
啟動(dòng)步驟:

  1. 啟動(dòng)一次 TestQuartz,叫做 a 應(yīng)用
  2. 緊接著(在幾秒鐘內(nèi))再次啟動(dòng) TestQuartz,叫做 b 應(yīng)用
  3. 使用多控制臺(tái)顯示方式,在兩個(gè)不同的控制臺(tái)觀察現(xiàn)象

上述相當(dāng)于兩個(gè)應(yīng)用做了集群。
運(yùn)行結(jié)果:
應(yīng)用a:

應(yīng)用b:

應(yīng)用a先執(zhí)行,運(yùn)行20秒,就自動(dòng)結(jié)束了。
應(yīng)用b在應(yīng)用a執(zhí)行期間,不會(huì)執(zhí)行。
應(yīng)用b在應(yīng)用b執(zhí)行結(jié)束之后,檢測(cè)到任務(wù)還未完成,自動(dòng)把后續(xù)任務(wù)執(zhí)行完畢。

http://www.risenshineclean.com/news/48529.html

相關(guān)文章:

  • 網(wǎng)站圖片大小愛(ài)站網(wǎng)關(guān)鍵詞搜索工具
  • 可以做網(wǎng)站首頁(yè)的圖片素材辦公軟件培訓(xùn)
  • 做團(tuán)購(gòu)網(wǎng)站的心得廣東今日最新疫情通報(bào)
  • 幫助傳銷做網(wǎng)站違法嗎市場(chǎng)推廣的方法和規(guī)劃
  • 做網(wǎng)站紙張大小合肥網(wǎng)絡(luò)關(guān)鍵詞排名
  • 網(wǎng)站開(kāi)發(fā)工作職責(zé)汽車軟文廣告
  • windows2008網(wǎng)站百度新聞首頁(yè)新聞全文
  • 創(chuàng)建網(wǎng)站要多長(zhǎng)時(shí)間在線培訓(xùn)平臺(tái)有哪些
  • 淘寶做個(gè)網(wǎng)站多少錢最新國(guó)際新聞熱點(diǎn)事件
  • 電子商務(wù)網(wǎng)站建設(shè)有哪些流程圖網(wǎng)站友情鏈接的好處
  • 網(wǎng)站寬度 自動(dòng)收縮微信公眾號(hào)怎么創(chuàng)建
  • 呼和浩特網(wǎng)站建設(shè)費(fèi)用網(wǎng)絡(luò)快速推廣渠道
  • 響應(yīng)式 網(wǎng)站建設(shè)seo系統(tǒng)培訓(xùn)班
  • 做網(wǎng)站要了解哪些非國(guó)產(chǎn)手機(jī)瀏覽器
  • 餐飲網(wǎng)站建設(shè)怎么建設(shè)的長(zhǎng)沙有實(shí)力的關(guān)鍵詞優(yōu)化價(jià)格
  • 昆明網(wǎng)站seo優(yōu)化上海app網(wǎng)絡(luò)推廣公司電話
  • 京東聯(lián)盟怎么做網(wǎng)站360推廣
  • 吃什么補(bǔ)腎治早射優(yōu)化seo培訓(xùn)班
  • 廣州營(yíng)銷型網(wǎng)站建設(shè)公司哪家靠譜百度關(guān)鍵字排名軟件
  • 番禺網(wǎng)站建設(shè)找哪家seo公司廣州
  • 住房建設(shè)網(wǎng)站柳州站長(zhǎng)工具網(wǎng)站排名
  • 草包做視頻網(wǎng)站北京今日重大新聞
  • 做衣服外單網(wǎng)站百度識(shí)圖在線識(shí)別網(wǎng)頁(yè)版
  • gta5資產(chǎn)網(wǎng)站正在建設(shè)現(xiàn)在陽(yáng)性最新情況
  • 橙子建站輸入了驗(yàn)證碼有危險(xiǎn)嗎sem工具是什么
  • 建筑工程招聘信息網(wǎng)seo優(yōu)化工具
  • 類似behance的設(shè)計(jì)網(wǎng)站seo顧問(wèn)張智偉
  • 手機(jī)網(wǎng)站cms手機(jī)百度助手
  • 服務(wù)器能放多少個(gè)網(wǎng)站廣州最新新聞
  • 國(guó)外扁平化網(wǎng)站設(shè)計(jì)欣賞優(yōu)化大師使用心得