Timer百框,和handler的post機(jī)制類似尖阔。都可以用于之后某個時刻執(zhí)行任務(wù)的實現(xiàn)浸锨,Timer恒存在自己的子線程,任務(wù)也在該子線程中執(zhí)行璧亚;handler.post出去的任務(wù)在什么線程執(zhí)行取決于其Looper所在線程讨韭。
一、簡介
1.1?Timer原理簡述
Timer是一個用于執(zhí)行定時任務(wù)的類癣蟋,可以單次執(zhí)行或按指定時間間隔循環(huán)執(zhí)行(直到主動cancel或線程被殺掉)透硝。Timer中任務(wù)處理采用了生產(chǎn)者-消費者模型的設(shè)計思想。具體知識點包含以下幾點:
1)一個存儲任務(wù)的任務(wù)池TaskQueue梢薪,包含一個初始大小為128的TimerTask數(shù)組蹬铺,負(fù)責(zé)任務(wù)的存儲(add)、排序(fixUp秉撇、fixDown)甜攀、取出(getMin)、清理(removeMin琐馆、quickRemove)规阀、循環(huán)任務(wù)處理(rescheduleMin)以及一些其他基本操作。并通過排序保證隊頭任務(wù)的執(zhí)行一定是最早的瘦麸。
2)一個作為事件消費者的TimerThread谁撼,TimerThread中不斷獲取當(dāng)前任務(wù)隊列的隊頭任務(wù),執(zhí)行任務(wù)滋饲。并根據(jù)任務(wù)是否需要循環(huán)決定是移除任務(wù)還是將任務(wù)按下一次執(zhí)行時間重新加入到任務(wù)隊列中厉碟。在TimerThread中不斷獲取待執(zhí)行任務(wù)時,采用了Object.wait()和Object.notify()的機(jī)制屠缭。Object.wait()保證了任務(wù)隊列為空時及時釋放資源箍鼓,而當(dāng)有新的任務(wù)時也通過Object.notify()及時恢復(fù)任務(wù)的遍歷。
3)TimerTask是任務(wù)實體呵曹,Runnable接口的實現(xiàn)類款咖。內(nèi)部包含用于線程安全的鎖lock、用于標(biāo)記任務(wù)狀態(tài)的字段state奄喂、以及一個供用戶實現(xiàn)的任務(wù)內(nèi)容抽象方法run().
4)Timer本身提供了對以上三者操作的封裝铐殃、實例化和對外暴露運行任務(wù)的接口。同時跨新,作為生產(chǎn)者富腊,將用戶任務(wù)加入到任務(wù)隊列;對消費者層面玻蝌,Timer也是和消費者線程唯一綁定的蟹肘,負(fù)責(zé)啟動消費者線程词疼,并在生產(chǎn)了新的任務(wù)后及時通知已經(jīng)休眠的消費者。提供了多種構(gòu)造方法和清理接口帘腹。
Timer是一個控制中心贰盗,對外和用戶交互,接收用戶要定時執(zhí)行的任務(wù)阳欲;對內(nèi)既是生產(chǎn)者又是消費者舵盈,控制 任務(wù)的存儲、調(diào)度球化、執(zhí)行的發(fā)起者秽晚。具體到TimerThread、TimerTask其實是一種委托思想(類似android中事件機(jī)制)筒愚,Timer委托二者一個作為生產(chǎn)者赴蝇、一個作為消費者。Timer不斷將新任務(wù)按序交給生產(chǎn)者保存巢掺,同時委托消費者線程不斷消費生產(chǎn)者隊列中待執(zhí)行的任務(wù)句伶,并根據(jù)是否循環(huán)進(jìn)行調(diào)度。
對于取消操作陆淀,消費者線程的根據(jù)newTasksMayBeScheduled字段和消費隊列是否為空雙重保障考余。而任務(wù)本身通過資深的狀態(tài)字段進(jìn)行控制。
1.2?Timer和Handler(或view)的post/postDelay
Timer和Handler.post都可以執(zhí)行延時任務(wù)轧苫。
二者的相同之處如下:
1)執(zhí)行的任務(wù)均為Runnable的實現(xiàn)類楚堤。
2)均可以指定延時時長delay。
3)二者皆通過生產(chǎn)者-消費者模型實現(xiàn)含懊。
二者的不同之處:
1)Timer的任務(wù)是在新開的子線程中執(zhí)行的身冬,所以不可以做更新UI的操作,但可以做耗時任務(wù)(對于存在多任務(wù)的case岔乔,不建議又耗時任務(wù)吏恭,因為耗時任務(wù)會影響后續(xù)任務(wù)的執(zhí)行時間);Handler.post方式執(zhí)行的任務(wù)是在Looper對應(yīng)線程中執(zhí)行的重罪,能否更新UI及做耗時任務(wù)取決于Looper對應(yīng)線程是否是主線程。
2)Handler.post的方式執(zhí)行任務(wù)只能執(zhí)行一次(可通過遞歸調(diào)用哀九、自調(diào)用的方式實現(xiàn)repeat)剿配;Timer封裝好了相關(guān)接口,并提供了兩種不同的循環(huán)方式阅束。
3)從代碼層面呼胚,Looper既是生產(chǎn)者(容器)也是消費者。并采用ThreadLocal機(jī)制將自身和線程一一綁定息裸,也就有了任務(wù)執(zhí)行取決于Looper的產(chǎn)生蝇更。具體下一篇再分析沪编。
4)handler中提供了handleMessage方法,是另一種消息分發(fā)年扩∫侠可以和以上兩種機(jī)制結(jié)合使用,用來切線程厨幻。
二相嵌、源碼分析
2.1 任務(wù)池TaskQueue
在其中存在一個初始大小128的array,根據(jù)注釋可以知道這是一個用做一個平衡二叉樹的模型况脆,一個父節(jié)點array[n]下掛載的兩個子節(jié)點為array[2n]和array[2n+1].
2.1.1 任務(wù)實體TimerTask
TimerTask是實現(xiàn)了Runnable的抽象類饭宾。
二叉樹的插入和刪除邏輯為
2.2 任務(wù)的消費者線程TimerThread
這樣消費者線程在任務(wù)隊列有任務(wù)時蛔溃,通過循環(huán)不斷執(zhí)行任務(wù)绰沥,無任務(wù)時,若想讓線程停止退出則要通過改變線程字段的方式贺待。如下:
1、隊列為空且newTasksMayBeScheduled成立麸塞,則wait等待
2秃臣、1不成立,且隊列為空(即newTasksMayBeScheduled不成立)哪工,則跳出循環(huán)奥此,線程執(zhí)行完畢跳出。再看run方法中finally中為清理工作雁比。
2.3 timer對外接口
結(jié)論:當(dāng)period<0時丈牢,不論任務(wù)執(zhí)行時間是否延誤祭钉,下一次都在固定時間執(zhí)行,參照系為當(dāng)前時間
當(dāng)period>0時己沛,任務(wù)在下一次時間后一定時間執(zhí)行慌核,參照系為下一次具體執(zhí)行時間。
三 使用方法
使用方法很簡單申尼,調(diào)用對應(yīng)方法即可遂铡。
最后有幾點需要注意:
1)task是一定執(zhí)行在timer子線程中(不論調(diào)用線程是否為主線程),所以若需要在任務(wù)中執(zhí)行更新ui的操作晶姊,可以通過runonuithread或顯示通過handler方式切回主線程。
2)在不使用時一定要及時cancel清理伪货,釋放資源们衙。
3)當(dāng)timer中有多任務(wù)時钾怔,因為后邊任務(wù)會依賴前邊任務(wù)執(zhí)行完,尤其是如果有耗時任務(wù)蒙挑,會發(fā)生定時不準(zhǔn)確的現(xiàn)象宗侦。
4)當(dāng)存在多任務(wù)時,若其中某個因異常而終止忆蚀,則會退出所有任務(wù)的執(zhí)行(消費者線程被異常終止了)
頭一次寫東西矾利,用來記錄自己的所學(xué)所獲,文筆不好馋袜,理解可能也有所片面男旗,希望看到的朋友不吝賜教,共同進(jìn)步欣鳖。