下面是一个Timer 的定时任务demo主要从两个方面进行讲解:
1、创建一个线程来执行定时任务
Timer timer = new Timer()
2、添加定时任务
timer.schedule(task, date, 10000)
public class TimerDemo { private static Timer timer = new Timer();//启动一个线程,run方法是个死循环 如 mainLoop所示: public static class MyTask extends TimerTask { @Override public void run() { System.out.println("要运行的定时任务执行了!!!!" + new Date()); } } public static class MyTask1 extends TimerTask { @Override public void run() { System.out.println("要运行的定时任务执行了!!!!" + new Date()); } } public static void main(String[] args) { try { MyTask task = new MyTask(); MyTask1 task1 = new MyTask1(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateString = "2018-5-5 18:59:00"; Date date = sdf.parse(dateString); String dateString1 = "2018-5-6 19:35:00"; Date date1 = sdf.parse(dateString1); System.out.println("字符串时间:" + date.toLocaleString() + "当前时间:" + new Date().toLocaleString()); timer.schedule(task, date, 10000);//此方法是把任务添加到排队队列中 // timer.schedule(task1, date1); } catch (Exception e) { e.printStackTrace(); } } }
mainLoop详细源码如下:从队列中取出任务执行
private void mainLoop() { while (true) { try { TimerTask task; boolean taskFired; synchronized(queue) { // Wait for queue to become non-empty while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait(); // 如果线程队列中没有要执行的任务就等待 if (queue.isEmpty()) break; // Queue is empty and will forever remain; die // Queue nonempty; look at first evt and do the right thing long currentTime, executionTime; task = queue.getMin();//从队列中取出要执行的任务 synchronized(task.lock) { if (task.state == TimerTask.CANCELLED) { queue.removeMin(); continue; // No action required, poll queue again } currentTime = System.currentTimeMillis();//当前时间 executionTime = task.nextExecutionTime;// 任务要执行的时间
//如果需要执行的任务的时间<当前的时间
if (taskFired = (executionTime<=currentTime)) { if (task.period == 0) { // Non-repeating, remove 单个任务不需要重复 直接从队列中移除不需要下次循环 queue.removeMin(); task.state = TimerTask.EXECUTED; } else { // Repeating task, reschedule queue.rescheduleMin(//这里是需要重复循环执行的任务period<0 ? currentTime - task.period : executionTime + task.period); } } } if (!taskFired) // Task hasn't yet fired; wait queue.wait(executionTime - currentTime);//如果是当前时间小于要执行的任务的时间,需要等待到时间后执行 } if (taskFired) // Task fired; run it, holding no locks task.run();//直接执行任务 } catch(InterruptedException e) {
//如果任务抛出异常,程序就结束了,不会再执行任务了
} } }}
把任务插入到排队队列中:
private void sched(TimerTask task, long time, long period) { if (time < 0) throw new IllegalArgumentException("Illegal execution time."); // Constrain value of period sufficiently to prevent numeric // overflow while still being effectively infinitely large. if (Math.abs(period) > (Long.MAX_VALUE >> 1)) period >>= 1; synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } queue.add(task);//把任务插入到排队队列中 然后进行排序 if (queue.getMin() == task)//取出小顶堆,也就是最近要执行的任务 queue.notify();//唤醒等待线程 就是 mainLoop方法中的 queue.notify() } }
在queue.add(task) 方法中,当添加一个对象时维护了一个小顶堆,每次取出来的是当前最近要执行的任务
private void fixUp(int k) { while (k > 1) { int j = k >> 1; if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime) break; TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } }
在mainLoop方法中,当一个任务完成后需要移除,需要重新维护小顶堆
private void fixDown(int k) { int j; while ((j = k << 1) <= size && j > 0) { if (j < size && queue[j].nextExecutionTime > queue[j+1].nextExecutionTime) j++; // j indexes smallest kid if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime) break; TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp; k = j; } }