多線程之----定時器TIMER


結上一篇  多線程的簡單介紹  http://www.cnblogs.com/duanxiaojun/p/6595847.html

在上一講中我主要是對多線程學習這個系列做了一個大致的學習計划,然后對實現線程的兩種方式做了介紹,但是在上一講中漏說了一點就是為什么java要提供集成Thread和實現runnable接口這兩種方式來實現線程,這個問題是我在面試的時候被問到的,很可惜之前從沒了解過為什么-------這也給自己一個教訓就是以后學什么東西要試着去問自己為什么是這樣的,人家為什么這樣去設計。好了針對這個問題在我查閱了很多資料后得出的是如下的解釋:

首先說一下,我們知道java的集成只能是單繼承,不能多集成,這樣的話就會有缺陷,比如想增加一個功能的時候必須要去修改基類。而實現runnable接口的這種方式可以很好的解決java不能多繼承導致的缺陷。這是第一個原因。

再說第二個,我們知道實現runnable接口的方式代碼的寫法是這樣的:new Thread(new runnable(){ public void run(){    ....}})。在這種情況下我們可以看到其實整個的runnable對象中的代碼可以被多個Thread對象實例所使用共享,這樣就可以解決一個多個線程處理同一資源的情況。做到了線程安全。在這里我覺着有必要通過一個代碼的方式來解釋一下第二個優點是如何實現的。我們拿一個賣火車票的例子,當然也可以是其他的有唯一資源的例子都可以。下面先看代碼如下和對代碼的解釋:

上面第對這個優點的一個代碼的展示。

好了 除了這兩個外 我們說其實在真正的項目中我們使用實現接口的方式是比較多的。

說到這里好像沒有說線程的一些狀態,線程有如下的幾種狀態:創建,就緒,堵塞,終止。對這四種狀態大家應該比較熟悉吧,這時候我又想起來一個面試的時候被問的,就是說說sleep和wait有什么區別,其實從字面意思也不難理解,sleep是睡眠,睡指定時候后就自己到就緒隊列中等待這cpu時間片的輪詢到的時候就占用cpu資源開始執行。而wait是等待,知道有人去主動的喚醒他notify或者喚醒全部notifyAll,在等待的時候是不占用資源的,也就是資源已經被釋放。其他的我想應該沒什么別的了。主要是看面試官想問什么了。

     好了上面是對上一篇的一個總結和補充,下面開始今天的有關javaTimer定時器的學習。

首先來說一下Timer是怎么工作的,Timer 是按照一定的時間段或者一個時間點根據定時的定時任務進行執行的。

Timer這個java提供的定時器有如下的特點:

① 他是一個單線程的,也就是你啟動一個Timer定時器就是啟動了一個線程。

② Timer定時器默認的情況下不是守護線程,但是可以通過構造參數設置為守護線程,守護線程在沒有其他線程的情況下自己會掛掉。

③ 使用Timer定時器的時候 要跟一個TimerTask定時任務結合來使用。而且TimerTask其實底層就是一個隊列,在TimerTask中增加的任務會在定時器這個線程里面挨個的執行。TimerTask也有自己的cannel取消等方法。

④ TimerTask中的run方法無法拋出,所以要進行try catch捕獲,如果其中任何一個任務發生異常沒有被捕獲,則其他任務也將被終止

說了這些概念,我們先來一個代碼例子來看看是這么執行的吧。

我們看到TImer定時器這個類有兩個schedule方法。其中都有的就是一個TimerTask這個任務。我對這兩個方法進行了一個總結-----網友提供。。

方法詳解:
(1)schedule(TimerTask task, Date executeTime)
當executeTime<=currentTime時,task任務會在currentTimer立即執行
當executeTime>currentTime時,task會在未來的executeTime執行
 
(2)schedule(TimerTask task, Date firstTime, long period)
當firstTime <=currentTime時,task任務會在currentTimer立即執行,
當firstTime >currentTime時,task會在未來的executeTime執行,
執行任務所用的時間taskUsedTime<peroid,則下一個任務執行的時間是上次任務執行完成的時間+peroid,任務按時間間隔peroid周期性執行任務
執行任務所用的時間taskUsedTime>peroid,則下一個任務執行的時間是上次任務執行完成的時間+taskUsedTime,任務按時間間隔taskUsedTime 周期性執行任務
 
 
(3)schedule(TimerTask task, long delay)
任務延遲delay毫秒進行執行
 
(4)schedule(TimerTask task, long delay, long period)
A、延遲delay毫秒第一次執行,
B、執行任務所用的時間taskUsedTime<peroid,則下一個任務執行的時間是上次任務執行完成的時間+peroid, 任務按時間間隔peroid周期性執行任務
C、執行任務所用的時間taskUsedTime>peroid,則下一個任務執行的時間是上次任務執行完成的時間+taskUsedTime, 任務按時間間隔taskUsedTime 周期性執行任務
 
(5)scheduleAtFixedRate(TimerTask task, long delay, long period)
 
(6)scheduleAtFixedRate(TimerTask task, Date firstTime,  long period)
         startTime = currentTime
A、當firstTime>currentTime,任務則在currentTime執行
B、當firstTime<currentTime,任務會發生追趕執行,追趕執行的次數expectCount=(currentTime-firstTime)/peroid+1;
  第一個peroid屬於追趕階段,如果追趕上則等待執行startTime+peroid時間任務,如果沒有追趕上則直接執行startTime+peroid時間的任務
 
對於Timer這個定時器的使用,我想掌握到這里就差不多了。但是還是接上一個的話題,我要知道java在實現這個定時器的時候到底是怎么做的呢,哪就讓我們去看看源碼吧,

 首先我們看一下Timer這個類的構造函數,因為我們知道我們再使用Timer這個類的時候我們只是創建了一個Timer對象,並沒有像Thread那樣主動的去調用start方法。所以我想答應也應該明白我們定時器的啟動是在構造函數中做的,沒錯,從源碼中我們可以得道驗證:

哈哈哈  沒錯吧,其實我們是Timer是一個單獨的線程,從第152行我們就可以看到,我們可以設置線程的名稱,可以設置是否是守護線程,然后調用start方法定時器就起作用了。但是並不會立即執行。線程調用start后也不會立即執行,這在上一篇中已經有說到了,他其實是把當前的線程示例放到了一個線程組中等待被執行。

哪我們就看他是如何調度的也就是schdule是如何執行的呢。

 

 

 這里我們補充一下,queue是一個TaskQueue,

好了對Timer的介紹今天就到這里吧,如有沒有說到的請各位評論一下,大家一塊學習。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM