今天小伙伴,拿過來一段代碼,說看是同步的一段代碼怎么會有異步的效果呢。代碼原型是:
他說這段代碼我知道能達到異步的效果,但是我不知道是怎么實現的。怎么看都好像有一個線程在等待結果,怎么會有異步效果呢。
我們開發的高并發服務,一般都會有一個工作線程池,用來響應客戶端同時發送過來的請求。每個在一個時間點都會獨立的處理一件事情。最常見的如下。
ExecutorService?
cachedThreadPool=newThreadPoolExecutor(500, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
newSynchronousQueue());
cachedThreadPool.execute(newRunnable() {
@Override
public voidrun() {
//todo list;
});
回調是最常見的異步并發模式,它有即時性高、接口設計簡單等。其缺點也非常明顯。首先,多線程環境下的回調一般是在觸發回調的模塊線程中執行的,這就意味著編寫回調方法時通常必須考慮線程互斥問題;其次,回調方式接口的提供者在本模塊的線程中執行用戶應用的回調也是相對不安全的,因為你無法確定它會花費多長時間或出現什么異常,從而可能間接導致本模塊的即時性和可靠性受影響;再者,使用回調接口不利于順序流程的開發,因為回調方法的執行是孤立的,要與正常流程匯合是比較困難的。因此回調接口適合于在回調中只需要完成簡單任務,并且不必與其它流程匯合的場景。
事件模式:
一般運用在Actor模型中:服務請求者向服務提供者發送消息,然后繼續進行后續不依賴服務處理結果的任務,在需要依賴結果前終止當前流程并記錄狀態;在等到回應消息后根據記錄的狀態觸發后續流程。這種基于狀態機的并發控制雖然比回調更適合于有延續性的順序流程,但開發者卻不得不將連續流程按照異步服務的調用切斷為多個按狀態區分的子流程,這樣又人為的增加了開發的復雜性。?
Future:
Boolean response = messageManager.sendSystemMessage(reqArgs);Future> future = RpcContext.getContext().asyncCall(new Callable>() {@Overridepublic? Boolean call() throws Exception {
// TODO Auto-generated method stub
return messageManager.sendNewSystemMessage(reqArgs);
}
});
response=future.get();
Future方式的好處,除了可以彌補以上方式的缺點外,還體現靈活在同步和異步的自由取舍,開發者可以根據流程的需要自由決定。上述代碼借鑒的是開源RPC框架DUBBO 的Future 設計,其中有是否需要等待Future.isDone(),何時等待Future.get(),等待多久Future.get(timeout)。比如可以根據數據是否就緒而決定要不要借這個空檔完成點其它任務,這對于實現“異步分支預測”機制是相當方便的。