自定义spring定时器
package com.wjz.quartz; import java.util.concurrent.Executors; public class QuartzDemo { public static void main(String[] args) throws Exception { new MyRunnable(Executors.newSingleThreadScheduledExecutor()).schedule(); // 这里让main线程睡眠是因为如果主线程执行完了MyRunnable对象就被销毁了实验效果无法展现 Thread.sleep(1000*60*5); } }
我可以看到初始化了一个任务线程延迟调度器ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();注入到了Runnable中
核心类MyRunnable实现了Runnable和ScheduledFuture接口
run方法中执行了任务调度
package com.wjz.quartz; import java.util.Date; import java.util.concurrent.Delayed; import java.util.concurrent.ExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.springframework.scheduling.support.SimpleTriggerContext; class MyRunnable implements Runnable, ScheduledFuture<Object> { private final ScheduledExecutorService executor; private final MyTrigger trigger = new MyTrigger(); private final SimpleTriggerContext triggerContext = new SimpleTriggerContext(); private final Object triggerContextMonitor = new Object(); private ScheduledFuture<?> currentFuture; private Date scheduledExecutionTime; public MyRunnable(ScheduledExecutorService executor) { this.executor = executor; } public ScheduledFuture<?> schedule() { synchronized (triggerContextMonitor) {
// 获得计划中的下一个执行时间 this.scheduledExecutionTime = trigger.nextExecutionTime(triggerContext); long delay = scheduledExecutionTime.getTime() - System.currentTimeMillis();
// 延时任务调度 this.currentFuture = executor.schedule(this, delay, TimeUnit.MILLISECONDS); return this; } } public void run() { Date actualExecutionTime = new Date(); System.out.println("------调用定时方法------"); Date completionTime = new Date(); synchronized (triggerContextMonitor) { triggerContext.update(scheduledExecutionTime, actualExecutionTime, completionTime); if (!this.currentFuture.isCancelled()) { schedule(); } } } public boolean cancel(boolean mayInterruptIfRunning) { synchronized (this.triggerContextMonitor) { return this.currentFuture.cancel(mayInterruptIfRunning); } } public boolean isCancelled() { synchronized (this.triggerContextMonitor) { return this.currentFuture.isCancelled(); } } public boolean isDone() { synchronized (this.triggerContextMonitor) { return this.currentFuture.isDone(); } } public Object get() throws InterruptedException, ExecutionException { ScheduledFuture<?> curr; synchronized (this.triggerContextMonitor) { curr = this.currentFuture; } return curr.get(); } public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { ScheduledFuture<?> curr; synchronized (this.triggerContextMonitor) { curr = this.currentFuture; } return curr.get(timeout, unit); } public long getDelay(TimeUnit unit) { ScheduledFuture<?> curr; synchronized (this.triggerContextMonitor) { curr = this.currentFuture; } return curr.getDelay(unit); } public int compareTo(Delayed other) { if (this == other) { return 0; } long diff = getDelay(TimeUnit.MILLISECONDS) - other.getDelay(TimeUnit.MILLISECONDS); return (diff == 0 ? 0 : ((diff < 0)? -1 : 1)); } }
触发器主要是返回触发时间
package com.wjz.quartz; import java.util.Date; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.TriggerContext; public class MyTrigger implements Trigger { private MySequence sequence = new MySequence(); public Date nextExecutionTime(TriggerContext triggerContext) { Date date = triggerContext.lastCompletionTime(); if (date == null) { date = new Date(); } return sequence.next(date); } }
计划时间表生成器主要是生成触发时间和返回下一个触发时间
package com.wjz.quartz; import java.util.BitSet; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.TimeZone; public class MySequence { private final BitSet seconds = new BitSet(60); MySequence() { setNumber(seconds, "0/5", 0, 60); } public Date next(Date date) { Calendar calendar = new GregorianCalendar(); calendar.setTime(date); calendar.setTimeZone(TimeZone.getDefault()); // 重置毫秒数 calendar.set(Calendar.MILLISECOND, 0); long originalTimestamp = calendar.getTimeInMillis(); doNext(calendar); if (calendar.getTimeInMillis() == originalTimestamp) { // 日历时间刚好到了原始时间戳时间,加一秒 calendar.add(Calendar.SECOND, 1); doNext(calendar); } return calendar.getTime(); } private void doNext(Calendar calendar) { int second = calendar.get(Calendar.SECOND); int nextSecond = seconds.nextSetBit(second); if (nextSecond == -1) { // 加一分钟 calendar.add(Calendar.MINUTE, 1); // 重置秒数 calendar.set(Calendar.SECOND, 0); nextSecond = seconds.nextSetBit(0); } if (second != nextSecond) { calendar.set(Calendar.SECOND, nextSecond); } } private static void setNumber(BitSet bitSet, String field, int min, int max) { String[] fields = field.split("/"); // 0, 5 int[] split = new int[2]; int start = split[0] = Integer.valueOf(fields[0]); int grow = split[1] = Integer.valueOf(fields[1]); int[] range = new int[2]; range[0] = split[0]; int end = range[1] = max - 1; for (int i = start; i < end; i += grow) { bitSet.set(i); } } }