我們?cè)陂_(kāi)發(fā)的時(shí)候,常常會(huì)有這樣的需要,需要保證某個(gè)操作只運(yùn)行一段時(shí)間,如果超時(shí)了,就執(zhí)行對(duì)應(yīng)的超時(shí)操作。
?
比如,在讀取網(wǎng)絡(luò)請(qǐng)求的時(shí)候,我們希望3秒內(nèi)能讀到數(shù)據(jù),如果超過(guò)了3秒沒(méi)有讀到,那么就不讀了,提示用戶(hù),超時(shí)了,需要重試。
比如,我們開(kāi)啟了一個(gè)進(jìn)程來(lái)執(zhí)行一條命令,這個(gè)命令可能是批量處理一批文件并生成一個(gè)報(bào)告,或者其它,我們知道這個(gè)命令肯定不會(huì)執(zhí)行超過(guò)30分鐘,那么,我們需要給它設(shè)定一個(gè)時(shí)間,如果超時(shí)了,那么我們就殺掉該進(jìn)程, 并清除掉錯(cuò)誤的生成數(shù)據(jù)。
比如,我們通過(guò)USB接口將設(shè)備如電紙書(shū),MP4等連接到電腦,如果嘗試連接了一段時(shí)間而沒(méi)有連接上,那么會(huì)給出指導(dǎo),讓用戶(hù)檢查設(shè)備或者進(jìn)行重試。
?
諸如此類(lèi),還有很多。
?
對(duì)于第一種情況,我們還有選擇,例如,我們可以通過(guò)設(shè)置socket的timeout時(shí)間來(lái)達(dá)到這個(gè)目的,但是對(duì)于大多數(shù)情況,它們都沒(méi)有給我們太多這樣原生的方式進(jìn)行選擇。
?
但是,對(duì)于這樣的需求,apache-common-exec包中的WatchDog還是給了我們一個(gè)很好的例子。
?
?
?
這是一個(gè)簡(jiǎn)單的監(jiān)聽(tīng)者模式的實(shí)現(xiàn),WatchDog是Subject,TimeoutObserver自然就是Observer,從上圖可以看出,WatchDog有著經(jīng)典Subject的3個(gè)職責(zé):
1. 管理Observer的職責(zé),如addTimeoutObserver(),removeTimeoutObserver()方法
2. 觸發(fā)Observer的職責(zé),如fireTimeoutOccured()
3. 自己本身的業(yè)務(wù)邏輯,在run()方法中。
?
從類(lèi)圖上看,可以看出WatchDog類(lèi)實(shí)現(xiàn)了Runnable接口,它在運(yùn)行時(shí)實(shí)際上是一個(gè)deamon線程,看它的start()方法的實(shí)現(xiàn):
?
?
public synchronized void start() { stopped = false; Thread t = new Thread(this, "WATCHDOG"); t.setDaemon(true); t.start(); }
而它自己本身的業(yè)務(wù)邏輯則很簡(jiǎn)單,就是判斷什么時(shí)候超時(shí)然后觸發(fā)TimeoutObserver的timeoutOccured(w : Watchdog) : void 方法:
?
?
public synchronized void run() { final long until = System.currentTimeMillis() + timeout; long now; while (!stopped && until > (now = System.currentTimeMillis())) { try { wait(until - now); } catch (InterruptedException e) { } } if (!stopped) { fireTimeoutOccured(); //trigger TimeoutObserver#timeoutOccred() operation } } protected final void fireTimeoutOccured() { Enumeration e = observers.elements(); while (e.hasMoreElements()) { ((TimeoutObserver) e.nextElement()).timeoutOccured(this); } }?
?
代碼很簡(jiǎn)單,是不是?當(dāng)我們有超時(shí)了需要進(jìn)行某種操作的需求時(shí),只需要將你需要進(jìn)行的操作放到實(shí)現(xiàn)了TimeoutObserver接口的類(lèi)中,比如:
?
?
public class NotifyUserTimeout implements TimeoutObserver { @Override public void timeoutOccured(Watchdog w) { System.out.println("Timeout happens.. exit the applicaton now"); System.exit(-1); } }?
然后調(diào)用WatchDog類(lèi)進(jìn)行超時(shí)時(shí)間的設(shè)置以及注冊(cè)實(shí)現(xiàn)的TimeoutObserver即可。
?
?
static main(args) { Watchdog watchDog=new Watchdog(3000);//set timeout for 3 seconds watchDog.addTimeoutObserver new NotifyUserTimeout() watchDog.start(); //simulate time-consuming task.. Thread.sleep 5000 println "finish normally.." }
?
?
從上可以看到,我們模擬了正常的操作大概需要5秒,但是設(shè)置了超時(shí)的時(shí)限為3秒,當(dāng)正常的操作超時(shí)后,會(huì)進(jìn)行提示用戶(hù)并且退出,上面的例子的結(jié)果輸出為:
?
Timeout happens.. exit the applicaton now
?
?
看吧,兩個(gè)簡(jiǎn)單的類(lèi),一個(gè)經(jīng)典的設(shè)計(jì)模式,便很好的詮釋了超時(shí)了該怎么辦這個(gè)需求。如果你有這樣的需求,不妨去試一試。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
