【并發技術11】Callable與Future的應用
Callable 接口類似于 Runnable,兩者都是為那些其實例可能被另一個線程執行的類設計的。但是 Runnable 不會返回結果,并且無法拋出經過檢查的異常。而 Callable 可以返回一個結果,這個返回值可以被 Future 拿到,也就是說,Future 可以拿到異步執行任務的返回值,下面來看一個簡單的例子:
public?class?CallableAndFuture?{????public?static?void?main(String[]?args)?{????????ExecutorService?threadPool?=?Executors.newSingleThreadExecutor();//?創建一個線程即可????????Future
使用并發庫創建一個線程,前面博文已經提到過,如果調用 execute 方法,要傳進去一個 Runnable,現在我調用 submit 方法,就可以傳進去一個 Callable 了,然后重寫 call 方法,即可返回一個我們需要的數據,然后我們用 Future 來接收返回的數據,通過?future.get()?方法就可以取到。
那么問題來了,這樣做不是更加麻煩?我還不如直接去調用一個方法,然后返回一個值,我立馬就拿到了啊,干嘛搞得這么麻煩!說的是有道理的,但是 Callable 和 Future 這個組合的用處不在于此。假設有一個很耗時的返回值需要計算,并且這個返回值不是立刻需要的話,那么就可以使用這個組合,用另一個線程去計算返回值,而當前線程在使用這個返回值之前可以做其它的操作,等到需要這個返回值時,再通過 Future 得到,這樣設計豈不是很好?
官方對 Future 有如下介紹:
Future 表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,并獲取計算的結果。計算完成后只能使用 get 方法來獲取結果,如有必要,計算完成前可以阻塞此方法。取消則由 cancel 方法來執行。還提供了其他方法,以確定任務是正常完成還是被取消了。一旦計算完成,就不能再取消計算。
查看 JDK 文檔,有個 cancel 方法是用來取消任務的,也就是說我們可以人為取消,這就比較靈活了,就像上面所說的,計算量比較大的時候,如果在不同情況下,是否需要去計算是不確定的,如果 xxx,就讓它算出結果,如果 xxx,就不用計算了,那我們可以很靈活的使用這個 Future,另外,在取消前,也可以先判斷是否已經執行完了。都有相關方法的。
上面是單個線程執行的情況,現在如果有多個線程都在執行,且有多個返回值,該怎么做呢?這種情況下,我們就要使用?CompletionService
public?class?CallableAndFuture?{????public?static?void?main(String[]?args)?{????????ExecutorService?threadPool?=?Executors.newCachedThreadPool();//定義一個緩存線程池????????CompletionService
這種方式和上面的方式有個區別是,上面單個線程的時候,使用 ExecutorService 對象去執行 submit,多個線程的時候就把線程池扔到?CompletionService
將生產新的異步任務與使用已完成任務的結果分離開來的服務。生產者 submit 執行的任務。使用者 take 已完成的任務,并按照完成這些任務的順序處理它們的結果。
通常,CompletionService 依賴于一個單獨的 Executor 來實際執行任務,在這種情況下,CompletionService 只管理一個內部完成隊列。
官方介紹跟上面寫的程序是一致的,首先 take 獲取已完成的任務,然后 get 將每個任務拿到。并且按照完成這些任務的順序處理它們,也就是說,剛剛在執行的時候,哪個線程先執行的,就會先拿到該線程執行的結果。
任務調度 計算
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。