Java多线程三
2016-03-02 13:38
459 查看
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
相关文章推荐
- Java多线程二
- java判断一个字符串是否可以转成日期(严格的日期转换)
- 反转排序
- 初学java
- Java多线程一
- jdk和jre的区别
- java.util.ArrayList.clone()是浅层拷贝
- Java EE框架
- [疯狂Java笔记]AWT:CardLayout卡堆布局
- JAVA单线程以及java多线程的实现方式
- 关于mac下eclipse 安装idk及配置jre
- JVM性能调优
- Eclipse“控制台”视图详解
- [疯狂Java笔记]AWT:GridLayout网格布局、GridBagLayout网格袋布局
- [疯狂Java笔记]AWT:BorderLayout方位布局
- Java8 日期/时间(Date Time)API指南
- WEB开发框架配置文件和各层注解(SpringMVC + Spring + Hibernate)
- java内存模型
- Java在String中添加双引号
- Spring 4.2.4.RELEASE MVC 学习笔记 - 6.1 - (咋个办呢 zgbn)