天天看點

多線程-有傳回結果Callable

作者:IT知識分享官

背景

最簡單的多線程是Runnable,最大的特點是:沒有傳回結果。

那怎麼才能有傳回結果?使用Callable。

官方文檔-Callable

java           

複制代碼

@FunctionalInterfacepublicinterfaceCallable<V>

A task that returns a result and may throw an exception. Implementors define a single method with no arguments called call.

傳回結果并可能引發異常的任務。實作者定義一個不帶參數的方法,稱為 call 。

The Callable interface is similar to Runnable, in that both are designed for classes whose instances are potentially executed by another thread. A Runnable, however, does not return a result and cannot throw a checked exception.

Callable 接口與 Runnable 類似,因為兩者都是為執行個體可能由另一個線程執行的類而設計的。但是, Runnable 不會傳回結果,也不能引發已檢查的異常。

The Executors class contains utility methods to convert from other common forms to Callable classes.

Executors 類包含從其他常見形式轉換為 Callable 類的實用方法。

源碼-Callable

java           

複制代碼

publicinterfaceCallable<V> {/** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */ V call()throws Exception; //和Runnable最大的差別就是有沒有傳回結果}

和Runnable最大的差別,就是有傳回資料。

Callable作用

Callable是Java中的一個接口,它位于java.util.concurrent包中。它的主要作用是允許你在多線程環境中執行可傳回結果的任務,并能夠擷取任務執行的結果或處理任務執行過程中的異常。

主要特點和作用如下:

  1. 可傳回結果: 與Runnable接口不同,Callable可以傳回一個結果。這個結果的類型由泛型參數指定,例如Callable<Integer>可以傳回一個整數結果。
  2. 異常處理: Callable的call方法可以抛出異常,你可以捕獲這些異常并進行适當的處理。
  3. 多線程任務執行: 你可以将Callable任務送出給ExecutorService的線程池來執行,這允許你在多個線程中并行執行任務。
  4. 擷取任務結果: 通過Future對象,你可以異步擷取任務執行的結果。Future提供了方法來等待任務完成并擷取其結果。
  5. 阻塞等待: 如果需要等待任務完成,可以使用Future的get方法,它會阻塞目前線程直到任務完成并傳回結果。

下面是一個簡單的示例,示範了如何使用Callable和ExecutorService來執行一個可傳回結果的任務:

java           

複制代碼

import java.util.concurrent.*;publicclassCallableExample {publicstaticvoidmain(String[] args)throws InterruptedException, ExecutionException {ExecutorServiceexecutorService= Executors.newSingleThreadExecutor(); Callable<Integer> task = () -> {// 在這裡執行耗時操作 Thread.sleep(2000);return42; }; Future<Integer> future = executorService.submit(task);// 這裡可以做一些其他的工作// 擷取任務執行結果,如果任務還未完成,會阻塞目前線程直到完成intresult= future.get(); System.out.println("任務結果:" + result); executorService.shutdown(); }}

總的來說,Callable使多線程程式設計更加靈活,允許你執行可傳回結果的任務,并能夠處理異常和擷取任務的執行結果。這對于需要并發處理任務的應用程式非常有用。

有了Runnable,為什麼還要Callable?

雖然Runnable和Callable都用于在多線程環境中執行任務,但它們之間存在一些重要的差別和應用場景,這就解釋了為什麼Java提供了這兩個不同的接口。

下面是一些差別和理由為什麼要使用Callable:

  1. 傳回結果:
  2. Runnable不傳回任何結果,它的run方法沒有傳回值。如果你需要任務執行後傳回一個結果,你必須使用其他機制(如執行個體變量或共享隊列)來擷取結果。
  3. Callable可以傳回一個結果,這個結果的類型由泛型參數指定。這讓任務的結果更容易通路和處理。
  4. 異常處理:
  5. Runnable的run方法不能抛出受檢查的異常(除非使用不推薦的Thread.setDefaultUncaughtExceptionHandler方法),是以它通常不适合處理可能會抛出異常的任務。
  6. Callable的call方法可以抛出受檢查的異常,這意味着你可以更容易地處理任務執行過程中的異常情況。
  7. Future對象:
  8. Callable任務送出後,會傳回一個Future對象,你可以使用這個對象來異步擷取任務的結果。這對于需要等待任務完成的情況非常有用,你可以在需要時阻塞等待結果。
  9. Runnable沒有内置的機制來擷取任務的執行結果,是以你需要自己實作一種方式來擷取結果。
  10. 适用性:
  11. Callable通常更适合需要執行、等待和處理任務結果的情況,特别是在并發程式設計和多線程環境中。
  12. Runnable通常更适合那些不需要傳回結果或不需要處理任務執行過程中的異常的簡單任務。

綜上所述,Callable和Runnable都有其獨特的用途和優勢。選擇哪個接口取決于你的具體需求,如果你需要任務傳回結果、處理異常,并且更進階的任務控制,那麼Callable可能更适合你。如果隻是執行簡單的任務而不需要傳回結果或處理異常,那麼Runnable可能足夠了。

Callable比Runnable優點

Callable 相對于 Runnable 具有一些明顯的優點,特别是在需要更豐富的多線程任務處理和結果擷取方面。以下是一些 Callable 相對于 Runnable 的優點:

  1. 傳回結果: 最大的優點之一是 Callable 允許任務傳回一個結果。這意味着任務可以執行一些計算或操作,并将結果傳回給調用者。這在處理需要計算或産生結果的并發任務時非常有用。
  2. 異常處理: Callable 的 call 方法可以抛出受檢查的異常,是以它更适合處理可能會出現異常情況的任務。這使得你能夠更好地處理任務執行過程中的錯誤情況。
  3. Future 對象: Callable 任務送出後,會傳回一個 Future 對象,允許你異步擷取任務的結果。這對于需要等待任務完成并在需要時擷取結果的情況非常有用。你可以使用 Future 的方法來等待任務完成,檢查任務是否已經完成,擷取結果,或者取消任務的執行。
  4. 更豐富的任務控制: Callable 接口與 Future 結合使用,提供了更多任務控制的能力。你可以取消任務的執行,設定任務的逾時時間,以及通過多個 Future 對象來協同執行多個任務。
  5. 泛型支援: Callable 使用泛型來指定傳回結果的類型,這增加了類型安全性。你可以明确指定任務傳回的資料類型,使代碼更具可維護性和可讀性。

總之,Callable 相對于 Runnable 提供了更多的功能和控制選項,使得多線程程式設計更加靈活和強大。然而,也要注意 Callable 的使用需要更多的代碼和處理,是以在簡單任務的情況下,選擇适用的接口是有必要的。