








摘要:異步調用是一種非阻塞式調用方式,用于在處理比較耗時的任務時保證程序性能不受到影響。實現異步調用的關鍵在于要解決三個技術問題,它們分別是程序阻塞問題、異步消息的傳遞問題和超時問題。本文介紹的開發方法和步驟采用并發線程、回調機制和計時器圓滿地解決了異步調用的技術難題。
關鍵詞:程序阻塞;異步消息傳遞;Java回調;線程;異步調用
中圖分類號:TP311 文獻標識碼:A
軟件模塊之間的調用關系可以分為兩大類:即同步調用和異步調用。在同步調用中,一段代碼(主調方)調用另一段代碼(被調方),主調方必須等待這段代碼執行完成返回結果后,才能繼續往下執行,所以,同步調用是一種阻塞式調用,主調方代碼一直阻塞等待直到被調方返回為止。同步調用相對比較直觀,也是大部分編程語言直接支持的一種調用方式。但是,同步調用在處理比較耗時的情況下會嚴重影響程序性能,影響人機交互的瞬時反應。例如,某個程序需要訪問數據庫獲取大量數據,然后根據這些數據進行一系列處理,將處理結果顯示在程序主窗口。由于數據庫訪問和大量數據的處理都是耗時的工作,在這個工作完成之前,處理結果遲遲不能顯示,用戶點擊鼠標也不會立即得到響應,讓用戶感到整個程序顯得很沉重。面對這樣一些需要比較長時間才能完成的應用場景,我們需要采用一種非阻塞式調用方式,即異步調用方式。在異步調用中,主調方調用被調方后,不等待對方返回結果就繼續執行后續代碼,被調方執行完畢后,通過某種手段通知調用方:結果已經出來,請酌情處理。我們可以對上面的例子改用異步調用將問題輕松化解:把整個耗時的工作放進一個單獨的線程,由主調方啟動此線程后繼續執行后續代碼,線程在背后悄悄地處理費時的工作,當工作完成,采用回調的方式通知主調方工作完成,主調方將結果顯示在主窗口。經過這樣的處理,主界面繼續進行自己的工作而不必死等,就不會造成界面響應遲鈍。
在實現異步調用機制時,除了線程之外,還要用到回調。回調是一種雙向調用,也就是,被調方在被調用時也會調用主調方的代碼。在異步調用中,被調方需要在工作完成時通知主調方,即調用主調方的接口,這一機制通過回調實現。回調和異步調用的關系非常緊密,回調是異步調用的基礎[1]。
本文理論聯系實際,首先闡述如何使用Java實現回調機制,然后進一步闡述使用Java回調和線程實現異步調用,最后,闡述在異步調用中如何處理超時問題。
1 Java回調機制的實現方法
實現Java回調,需要做如下三件事情:
(1)定義一個回調接口CallbackInterface
接口中聲明回調方法handle,如圖1所示,回調方法就是一個普通的方法,接收一個消息字符串或者一個封裝了數據的事件。
(2)定義一個類實現回調接口
這個類其實就是消息接收者和處理者,如圖2所示,其中:回調方法是消息發生時實際處理消息的方法,此處簡化為一條打印語句。
(3)定義消息通知者
消息通知者必須具備兩種能力,第一,它必須知道誰是消息接收者,第二,當消息發生時,它能夠回調這些接收者的回調方法。為了獲得這兩種能力,消息通知者首先必須提供一個注冊方法register, 通過注冊的方式來注冊多個對此消息或事件感興趣的對象。然后提供一個消息通知方法notifyMessage,在這個方法中調用所有消息接收者的回調方法。具體代碼如圖3所示。
上述代碼使用了一個可變數組List
有了消息接收者和消息通知者,就可以完成消息通知機制了,圖4給出的是測試代碼。
這里有一個非常關鍵的步驟就是將消息接收者向消息通知者注冊,只有已注冊的對象才會收到消息通知。
值得一提的是,Java回調機制的使用非常廣泛, 比如Java的事件監聽器模式和觀察者模式都包含了回調機制[2],在一些框架API提供的調用中不少也是以回調的形式提供的[3]。深刻理解Java回調機制是很有裨益的。
運行結果如圖5所示。
2 使用Java回調和線程實現異步調用
線程是一個獨立的執行流,其本質是程序中一段并發執行的代碼。在異步調用機制中引入線程,在線程中完成耗時的工作,其目的是讓調用方的主線程繼續執行后續代碼而不需要等待被調方的結果返回。由于不需要等待,這樣我們就等于同時做了兩件事情,而這兩件事情分別是在不同的執行流中執行,主調者在當前的主線程中執行,被調者在另外一個線程中執行,因此提高了程序的效率,避免了界面的響應遲鈍。當被調者執行完成后,仍然采用回調通知主調者。
如圖6所示,LongTimeWorker是一個用于完成耗時工作的線程,同時又是消息通知者。其耗時工作在run方法中完成,另外提供一個注冊方法register, 和一個消息通知方法notifyMessage,在run方法的最后,即耗時工作完成以后,調用notifyMessage將消息廣播出去。
將前面的測試代碼做一點改動就可以看到異步調用的效果如圖7所示。
3 異步調用中超時問題的處理
異步調用通常都要加入超時機制,因為我們總是希望在一個指定的時間范圍內返回一個結果,即使沒有得到結果也該有個超時通知。這時我們需要使用“限時線程回調方式”,它在原有線程回調的基礎上加上一個計時器Timer以計算消耗的時間,如果時間期限到了任務還沒有執行完成即中斷線程,并將超時消息廣播出去。LongTimeWorker類需要修改部分的代碼如圖8和圖9所示。
首先LongTimeWorker線程類增加了一個構造方法,其參數是超時時間timeout,構造方法的主要任務是創建一個定時器,每秒鐘計時一次,若超時時間到則終止本線程,并廣播超時消息。LongTimeWorker線程類的第二個改變發生在其run方法中,線程一啟動立即開始計時,完成工作后停止計時,并廣播消息。
4 結束語
異步調用是一種非阻塞式調用方式,用于在處理比較耗時的任務時保證程序性能不受到影響。實現異步調用的關鍵在于要解決三個技術難題,它們分別是程序阻塞問題、異步消息的傳遞問題和超時問題。本文介紹的方法采用并發線程、回調機制和計時器使上述問題得到了圓滿解決。
參考文獻:
[1] 陳家朋.異步消息的傳遞-回調機制[EB/OL]. http://www.ibm.com/developerworks/cn/linux/l-callback/, 2003.
[2] Eric Freeman.Head First Design Pattern[M].O’Reilly Media, Inc. 2004:51-53.
[3] 羅時飛.精通Spring-深入Java EE開發核心技術[EB/OL] , 回調接口集合及其觸發順序http://book.51cto.com/art/201004/193405.htm.
作者簡介:
錢宇虹,女,計算機科學碩士.從事軟件開發與應用、軟件
工程、軟件測試技術方面的教學、科研和開發.