并發技術11】Callable與Future的應用

      網友投稿 633 2025-03-31

      Callable 接口類似于 Runnable,兩者都是為那些其實例可能被另一個線程執行的類設計的。但是 Runnable 不會返回結果,并且無法拋出經過檢查的異常。而 Callable 可以返回一個結果,這個返回值可以被 Future 拿到,也就是說,Future 可以拿到異步執行任務的返回值,下面來看一個簡單的例子:

      public?class?CallableAndFuture?{????public?static?void?main(String[]?args)?{????????ExecutorService?threadPool?=?Executors.newSingleThreadExecutor();//?創建一個線程即可????????Future?future?=?threadPool.submit(????????????????new?Callable()?{????????????????????????????????????????@Override????????????????????public?String?call()?throws?Exception?{????????????????????????Thread.sleep(2000);????????????????????????return?"hello";????????????????????}????????????????}???????????????);????????System.out.println("等待結果:");????????try?{????????????System.out.println("拿到結果:"?+?future.get());????????}?catch?(Exception?e)?{????????????//?TODO?Auto-generated?catch?block????????????e.printStackTrace();????????}?}

      使用并發庫創建一個線程,前面博文已經提到過,如果調用 execute 方法,要傳進去一個 Runnable,現在我調用 submit 方法,就可以傳進去一個 Callable 了,然后重寫 call 方法,即可返回一個我們需要的數據,然后我們用 Future 來接收返回的數據,通過?future.get()?方法就可以取到。

      那么問題來了,這樣做不是更加麻煩?我還不如直接去調用一個方法,然后返回一個值,我立馬就拿到了啊,干嘛搞得這么麻煩!說的是有道理的,但是 Callable 和 Future 這個組合的用處不在于此。假設有一個很耗時的返回值需要計算,并且這個返回值不是立刻需要的話,那么就可以使用這個組合,用另一個線程去計算返回值,而當前線程在使用這個返回值之前可以做其它的操作,等到需要這個返回值時,再通過 Future 得到,這樣設計豈不是很好?

      【并發技術11】Callable與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?completionService?=?????????????????new?ExecutorCompletionService(threadPool);?//將線程池扔進去????????for(int?i?=?1;?i?<=?5;?i?++)?{????????????final?int?seq?=?i;????????????completionService.submit(?//用里面裝的線程去執行這些任務,每個線程都會返回一個數據????????????????????new?Callable?()?{??????????????????????????????????????????????@Override????????????????????????public?Integer?call()?throws?Exception?{????????????????????????????Thread.sleep(new?Random().nextInt(5000));????????????????????????????return?seq;????????????????????????}????????????????????}????????????????);????????}????????for(int?i?=?0;?i?

      這種方式和上面的方式有個區別是,上面單個線程的時候,使用 ExecutorService 對象去執行 submit,多個線程的時候就把線程池扔到?CompletionService?中去,然后執行 submit,最后我們在調用?take()?和?get()?方法取出結果即可。使用起來比較方便,下面來看一下 JDK 文檔對其的介紹:

      將生產新的異步任務與使用已完成任務的結果分離開來的服務。生產者 submit 執行的任務。使用者 take 已完成的任務,并按照完成這些任務的順序處理它們的結果。

      通常,CompletionService 依賴于一個單獨的 Executor 來實際執行任務,在這種情況下,CompletionService 只管理一個內部完成隊列。

      官方介紹跟上面寫的程序是一致的,首先 take 獲取已完成的任務,然后 get 將每個任務拿到。并且按照完成這些任務的順序處理它們,也就是說,剛剛在執行的時候,哪個線程先執行的,就會先拿到該線程執行的結果。

      任務調度 計算

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:非常棒的 Excel 超鏈接功能可以跳轉到網址和郵箱等(非常棒的成語)
      下一篇:微信怎么在線編輯電子表格(微信怎么弄表格在線編輯)
      相關文章
      亚洲精品福利网站| 少妇中文字幕乱码亚洲影视| 久久久亚洲欧洲日产国码二区| 亚洲码国产精品高潮在线| 亚洲日韩国产精品乱| 亚洲美女在线国产| 国产黄色一级毛片亚洲黄片大全| 亚洲真人日本在线| 亚洲人成色77777在线观看大 | 亚洲欧洲视频在线观看| 久久亚洲sm情趣捆绑调教| 亚洲小视频在线播放| 亚洲国产片在线观看| 国产日本亚洲一区二区三区 | 亚洲五月综合缴情在线观看| 亚洲乳大丰满中文字幕| 亚洲人精品午夜射精日韩| 好看的电影网站亚洲一区| 久久精品国产亚洲AV麻豆~| 亚洲成人在线电影| 亚洲最大的成网4438| 久久亚洲精品人成综合网| 亚洲精品一卡2卡3卡三卡四卡| 亚洲国产视频网站| 亚洲六月丁香六月婷婷蜜芽| 国产亚洲精品成人AA片| 在线观看亚洲免费| 国产成人精品久久亚洲高清不卡 | 中文字幕亚洲天堂| 亚洲第一成年男人的天堂| 亚洲福利一区二区| 亚洲中文字幕无码中文| 亚洲AV噜噜一区二区三区| 亚洲国产小视频精品久久久三级| 中文字幕亚洲专区| 久久精品亚洲精品国产色婷| 亚洲国产亚洲片在线观看播放 | 亚洲精品乱码久久久久久V| 亚洲 国产 图片| 亚洲夜夜欢A∨一区二区三区| 国产V亚洲V天堂A无码|