1. 基本概念
java.util.Timer:是一個實用工具類,該類用來調度一個線程(schedule a thread),使它可以在將來某一時刻執行。 Java的Timer類可以調度一個任務運行一次,或定期循環運行。 Timer tasks should complete quickly. 即定時器中的操作要儘可能花費短的時間。
java.util.TimerTask:是一個抽象類,它實現了Runnable接口。我們需要擴展該類以便創建自己的TimerTask,這個TimerTask可以被Timer調度。
注意:默認, task執行線程不是daemon線程, 任務執行完,主線程(或其他啓動定時器的線程)結束時,task線程並沒有結束。如果調用者想要快速終止計時器的任務執行線程,調用者應該調用timer.cancel()
方法。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">timerTest</span>() { Timer myTimer = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Timer(); myTimer.schedule(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TimerTask() { @Override <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"1s後運行"</span>); myTimer.cancel(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 需要手動cancel</span> } }, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
2. 源碼解析及案例
Timer類是線程安全的,多進程不需要外部同步機制就可以共享同一個Timer對象。創建Timer對象,會創建一個java.util.TaskQueue實例,在執行定時任務時,將taskqueue對象作爲鎖,在指定時間間隔添加任務,在任何時刻只能有一個線程執行TimerTask。
Timer類使用對象的wait和notify方法來調度任務。
查看Timer源代碼:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// TaskQueue隊列,內部就是一個TimerTask[]數組</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TaskQueue queue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TaskQueue(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Timer內部維持一個叫TimerThread的線程,傳遞TaskQueue隊列</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> TimerThread thread = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TimerThread(queue); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 創建Timer即啓動線程</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Timer</span>(String name) { thread.setName(name); thread.start();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 啓動線程,後面有分析TimerThread的run方法</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">schedule</span>(TimerTask task, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> delay) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (delay < <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalArgumentException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Negative delay."</span>); sched(task, System.currentTimeMillis()+delay, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 核心調度方法,time表示執行的絕對時間</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">sched</span>(TimerTask task, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> time, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> period) { ... <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// timer對象中的queue作爲鎖</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span>(queue) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!thread.newTasksMayBeScheduled) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalStateException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Timer already cancelled."</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span>(task.lock) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (task.state != TimerTask.VIRGIN) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalStateException( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Task already scheduled or cancelled"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 設置下次執行的時間</span> task.nextExecutionTime = time; task.period = period; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 設置task爲調度狀態</span> task.state = TimerTask.SCHEDULED; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 將當前待執行的task添加到隊列中</span> queue.add(task); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 隊列中取出的head task爲當前task</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (queue.getMin() == task) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 在任何時刻只能有一個線程執行TimerTask</span> queue.notify(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li></ul>
其中Timer中啓動的TimerThread的run方法:
<code class="hljs cpp has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> TaskQueue <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>; TimerThread(TaskQueue <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span> = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> run() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { mainLoop(); } finally { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Someone killed this Thread, behave as if Timer cancelled</span> synchronized(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>) { newTasksMayBeScheduled = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.clear(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Eliminate obsolete references</span> } } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> mainLoop() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { TimerTask task; boolean taskFired; synchronized(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果queue隊列爲空,則將線程阻塞,等待task</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.isEmpty() && newTasksMayBeScheduled) <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.wait(); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.isEmpty()) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">break</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Queue is empty and will forever remain; die</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Queue nonempty; look at first evt and do the right thing</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> currentTime, executionTime; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 隊列中獲取task</span> task = <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.getMin(); synchronized(task.lock) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 此處說明可以通過cancel()設置終止task的執行,但TimerThread並沒有終止</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (task.state == TimerTask.CANCELLED) { <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.removeMin(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 從隊列中移除</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// No action required, poll queue again</span> } currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (taskFired = (executionTime<=currentTime)) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (task.period == <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Non-repeating, remove</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.removeMin(); task.state = TimerTask.EXECUTED; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Repeating task, reschedule</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.rescheduleMin( task.period<<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> ? currentTime - task.period : executionTime + task.period); } } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 還未到執行時間,則等待相應的時間</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!taskFired) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Task hasn't yet fired; wait</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.wait(executionTime - currentTime); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (taskFired) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Task fired; run it, holding no locks</span> task.run(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 執行task的run方法!</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span>(InterruptedException e) { } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li></ul>
TimerTask的調度流程:由以上分析可知,當我們創建一個Timer時,同時內部創建了一個TimerThread線程,並啓動它,該線程會不斷掃描從Timer傳遞進來的task隊列,如果爲空,則wait()阻塞該線程;當timer調用shedule方法的時候,將傳遞的task添加到隊列中,同時調用queue.notify()
方法喚醒TimerThread線程,則從隊列中取出task根據給定的等待時間wait等待,等待完成後執行task.run();
啓動任務。(這種結構可以應用到簡單的爬蟲中)
如何終止Timer線程:
默認情況下,創建的timer線程會一直執行,一般通過下面的方式來終止timer線程:
- 調用timer的cancle方法
- 把timer線程設置成daemon線程,(new Timer(true)創建daemon線程),在jvm裏,如果所有用戶線程結束,那麼守護線程也會被終止,不過這種方法一般不用。
下面給出一個Timer執行多個task的簡單案例:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">multileTasksShareOneTimer</span>() { Timer myTimer = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Timer(); TimerTask task1 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TimerTask() { @Override <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(Thread.currentThread().getName() +<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" 1s後執行task1"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//myTimer.cancel();</span> } }; TimerTask task2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TimerTask() { @Override <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { System.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">out</span>.println(Thread.currentThread().getName() +<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" 2s後執行task2"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//myTimer.cancel();</span> } }; myTimer.schedule(task1, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// task2.cancel();</span> myTimer.schedule(task2, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2000</span>); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li></ul>
運行輸出:注意此時Timer的TimerThread並沒有結束,因爲在mainLoop()等待task而wait進入阻塞狀態!
如果設置了task2.cancel();則調度執行task2會拋出異常:
定時器實際使用的場景還是很多的,比如下面的,在每天零晨備份數據庫,等等。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 每天0晨備份數據庫 */</span> <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@SuppressWarnings</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"deprecation"</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">backupDatabase</span>() { Timer timer = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Timer(); TimerTask task = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TimerTask() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 備份數據庫</span> System.out.println(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"數據庫備份..."</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// other operation</span> } }; Date firstTime = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Date(); firstTime.setHours(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); firstTime.setMinutes(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); firstTime.setSeconds(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> oneDayPeriod = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>; timer.scheduleAtFixedRate(task, firstTime, oneDayPeriod); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// timer.schedule(task, firstTime, oneDayPeriod);</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
最後:如果是簡單的定時調度,使用Timer就夠了,如果複雜的調度任務,可以考慮使用Quartz