《Java并发编程实战》一书提到的用ExecutorService取代Java Timer有几个理由,我认为其中最重要的理由是:
如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以 TimerTask抛出的未检查的异常会终止timer线程。这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。
stackoverflow上也有关于此问题的讨论:
http://stackoverflow.com/questions/409932/java-timer-vs-executorservice
Timer的问题:
Java代码
1 package com.ljn.timer;
2
3 import java.util.Date;
4 import java.util.Timer;
5
6 /**
7 * @author lijinnan
8 * @date:2013-11-25 下午3:27:43
9 */
10 public class TimerException {
11
12 public static void main(String[] args) {
13 System.out.println("start:" + new Date());
14 Timer timer = new Timer();
15 int delay = 1000;
16 int period = 2000;
17 timer.schedule(new OKTask(), delay * 2, period); //"OKTask" does not get chance to execute
18 timer.schedule(new ErrorTask(), delay, period); //exception in "ErrorTask" will terminate the Timer
19 }
20
21 /*输出:
22 start:Mon Nov 25 17:49:53 CST 2013
23 ErrorTask is executing...
24 error:Mon Nov 25 17:49:55 CST 2013
25 Exception in thread "Timer-0" java.lang.RuntimeException: something wrong
26 at com.ljn.timer.ErrorTask.run(ErrorTask.java:14)
27 */
28
29 }
用ExecutorService则正常:
Java代码
30 package com.ljn.timer;
31
32 import java.util.Date;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.ScheduledExecutorService;
35 import java.util.concurrent.TimeUnit;
36
37 /**
38 * @author lijinnan
39 * @date:2013-11-25 下午3:35:39
40 */
41 public class ScheduledExecutorServiceTest {
42
43 public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
44
45 public static void main(String[] args){
46 System.out.println("start:" + new Date());
47 ErrorTask errorTask = new ErrorTask();
48 OKTask okTask = new OKTask();
49 int delay = 1000;
50 int period = 2000;
51 scheduledExecutorService.scheduleAtFixedRate(errorTask, delay, period, TimeUnit.MILLISECONDS); //"ErrorTask" throws Exception and then stopes.
52 scheduledExecutorService.scheduleAtFixedRate(okTask, delay * 2, period, TimeUnit.MILLISECONDS); //"OKTask" is executed periodically, not affected by "ErrorTask"
53
54 //scheduledExecutorService.shutdown();
55 }
56
57 /*
58 start:Mon Nov 25 17:54:22 CST 2013
59 ErrorTask is executing...
60 error occurs:Mon Nov 25 17:54:24 CST 2013
61 OKTask is executed:Mon Nov 25 17:54:24 CST 2013
62 OKTask is executed:Mon Nov 25 17:54:26 CST 2013
63 OKTask is executed:Mon Nov 25 17:54:28 CST 2013
64 ......
65 */
66
67 }
另外开发中常常会让任务在每天的指定时间点运行,示例如下:
Java代码
68 package com.ljn.timer;
69
70 import java.util.Date;
71 import java.util.concurrent.Executors;
72 import java.util.concurrent.ScheduledExecutorService;
73 import java.util.concurrent.TimeUnit;
74
75 /**
76 * @author lijinnan
77 * @date:2013-11-25 下午5:18:55
78 */
79 public class FixedDatetimeTaskTest {
80
81 public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
82
83 public static void main(String[] args) throws Exception {
84 System.out.println("start:" + new Date());
85
86 //每天的02:30:00执行任务
87 long delay = Helper.calcDelay(2, 30, 0);
88 long period = Helper.ONE_DAY;
89 scheduledExecutorService.scheduleAtFixedRate(new OKTask(), delay, period, TimeUnit.MILLISECONDS);
90 }
91
92 }
文章中用到的其他类:
Java代码
93 package com.ljn.timer;
94
95 import java.util.Date;
96 import java.util.TimerTask;
97
98 public class ErrorTask extends TimerTask {
99
100 @Override
101 public void run() {
102 try {
103 System.out.println("ErrorTask is executing...");
104 Thread.sleep(1000);
105 System.out.println("error occurs:" + new Date());
106 throw new RuntimeException("something wrong");
107 } catch (InterruptedException e) {
108 }
109 }
110
111 }
Java代码
112 package com.ljn.timer;
113
114 import java.util.Date;
115 import java.util.TimerTask;
116
117
118 public class OKTask extends TimerTask {
119
120 @Override
121 public void run() {
122 System.out.println("OKTask is executed:" + new Date());
123 }
124 }
Java代码
125 package com.ljn.timer;
126
127 import org.joda.time.DateTime;
128
129 /**
130 * @author lijinnan
131 * @date:2013-11-25 下午5:17:40
132 */
133 public class Helper {
134
135 private Helper() {}
136
137 public static final long ONE_DAY = 60 * 60 * 24;
138
139 public static long calcDelay(int hour, int minute, int second) {
140 if (!(0 <= hour && hour <=23 && 0 <= minute && minute <=59 && 0 <=second && second <= 59)) {
141 throw new IllegalArgumentException();
142 }
143 return calcDelay(fixed(hour, minute, second));
144 }
145
146 private static long calcDelay(DateTime targetDatetimeOfToday) {
147 long delay = 0;
148 DateTime now = new DateTime();
149
150 //时间点已过,只好延时到明天的这个时间点再执行
151 if (now.isAfter(targetDatetimeOfToday)) {
152 delay = now.plusDays(1).getMillis() - now.getMillis();
153
154 //时间点未到
155 } else {
156 delay = targetDatetimeOfToday.getMillis() - now.getMillis();
157 }
158
159 return delay;
160 }
161
162 /**
163 * 返回这样一个DateTime对象:
164 * 1.日期为今天
165 * 2.时分秒为参数指定的值
166 * @param hour 0-23
167 * @param minute 0-59
168 * @param second 0-59
169 * @return
170 */
171 private static DateTime fixed(int hour, int minute, int second) {
172
173 return new DateTime()
174 .withHourOfDay(hour).withMinuteOfHour(minute).withSecondOfMinute(second);
175 }
176
177 }