我是靠谱客的博主 烂漫黑夜,这篇文章主要介绍定时任务之Timer定时器,现在分享给大家,希望可以做个参考。

文章目录

      • 使用例子
      • 常用API
      • 工作原理
      • 总结

使用例子

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.myself.study; import java.util.Timer; import java.util.TimerTask; public class TimerDemo { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("timer执行业务逻辑..."); } }, 1000, 1000); Timer timer1 = new Timer(); timer1.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println("timer1执行业务逻辑..."); } }, 1000, 1000); } }

常用API

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
// delay延时之后执行task,只执行一次 public void schedule(TimerTask task, long delay); // 当时间到达time指定的时间时执行task,只执行一次 public void schedule(TimerTask task, Date time); // delay延时之后执行一次task,然后每隔period时间执行一次task public void schedule(TimerTask task, long delay, long period); // 当时间到达firstTime指定的时间时执行一次task,然后每隔period时间执行一次task public void schedule(TimerTask task, Date firstTime, long period); // delay延时之后执行一次task,然后每隔period时间执行一次task public void scheduleAtFixedRate(TimerTask task, long delay, long period); // 当时间到达firstTime指定的时间时执行一次task,然后每隔period时间执行一次task public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period);

Timer常用的API就是上述6个以schedule开头的方法,大体分为单次调度和周期性调度两类。其中对于周期性调度的方法需要特别说明的是,schedule和scheduleAtFixedRate正常情况下功能无差,但是在特殊情况下就会有部分差异,那就是当正在被调度的任务执行耗时很长,超过了period指定的时间间隔,schedule调度会在(任务结束时间 + period时间间隔)点再调度下次任务,而scheduleAtFixedRate调度则会尽量按照period对应的原始时间点调度下次任务。
比如,有一个任务原定周期执行间隔10s,0s处开始执行一次任务,因某些原因耗时13s,那么schedule和scheduleAtFixedRate运行时间点分别如下:
schedule:0s 13s 23s 33s …
scheduleAtFixedRate: 0s 13s 20s 30s …

工作原理

Timer对象内部持有一个TimerThread工作线程以及一个TaskQueue工作队列,调度任务首先通过Timer的schdule*相关方法提交到TaskQueue任务队列中,然后TimerThread工作线程业务逻辑中,通过while(true)死循环不断从TaskQueue队列中每次取出一个任务调用其run方法执行,所以说Timer定时器调度任务是单线程的,如果正在被调度的任务耗时太长就会阻塞TaskQueue队列中其他任务的执行。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
class TimerThread extends Thread { /** * This flag is set to false by the reaper to inform us that there * are no more live references to our Timer object. Once this flag * is true and there are no more tasks in our queue, there is no * work left for us to do, so we terminate gracefully. Note that * this field is protected by queue's monitor! */ boolean newTasksMayBeScheduled = true; /** * Our Timer's queue. We store this reference in preference to * a reference to the Timer so the reference graph remains acyclic. * Otherwise, the Timer would never be garbage-collected and this * thread would never go away. */ private TaskQueue queue; TimerThread(TaskQueue queue) { this.queue = queue; } public void run() { try { mainLoop(); } finally { // Someone killed this Thread, behave as if Timer cancelled synchronized(queue) { newTasksMayBeScheduled = false; queue.clear(); // Eliminate obsolete references } } } /** * The main timer loop. (See class comment.) */ 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( task.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) { } } } }

主要逻辑就位于TimerThread类中,可以看到TimerThread的mainLoop方法中,主逻辑被while(true)死循环包裹,从队列中依次取出一个任务执行,这个主逻辑虽然被try/cache包裹,但是只会捕获InterruptedException 异常,一旦出现其他异常,mainLoop方法就会退出,接着TimerThread的run方法也会退出,这也就意味着这个线程因异常而停止运行了,那么Timer定时器也就没有用了。

总结

  1. Timer定时器单线程执行,执行时间长的任务会阻塞其他任务,即使已经到了调度时间。
  2. Timer定时器调度的任务如果抛出异常,TimerThread线程就会退出,Timer定时器也就没用了。
  3. Timer定时器比较古老,现在用的比较少了,权当了解。

最后

以上就是烂漫黑夜最近收集整理的关于定时任务之Timer定时器的全部内容,更多相关定时任务之Timer定时器内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(64)

评论列表共有 0 条评论

立即
投稿
返回
顶部