1. 程式人生 > 其它 >Java 多執行緒: Runnable 介面和 Callable 介面的異同(附程式碼示例)

Java 多執行緒: Runnable 介面和 Callable 介面的異同(附程式碼示例)

技術標籤:Javathreadjava多執行緒

Runnable 自 Java 1.0 時就有了,而 Callable 介面在 Java 1.5 時才被加入。兩者都是 Functional 介面,也就是說可以直接使用 Lambda 表示式來實現執行緒函式,不一定非得實現一個類來實現介面。Runnable 可以直接傳給 Thread 構造方法,Callable 不可以。 Callable 只能使用 ExecutorService,但是 Callable 可以返回執行緒的執行結果,Runnable 不可以,如果使用 Lambda 表示式來獲得執行緒函式的執行結果,則需要一點小技巧。

下面是示例程式碼和它的執行結果。這段程式使用一個單獨的執行緒來計算階乘,然後輸出結果。可以看到,使用 Callable 可以直接通過 future.get().intValue 得到結果,而 Runnable 中我們先聲明瞭一個 Lambda 外的本地變數,然後在 Lambda 表示式中賦值得到的結果。這個本地變數的型別很特殊,這是因為 Java 對在 Lambda 裡改變本地變數的限制造成的。

Callable 的 future 結果還可以通過 getCause 來得到執行緒函式中的異常,雖然兩者都可以通過 ExecutionException 捕捉到執行異常。

public class Main {

    public static void main(String[] args) {
        factorialWithRunnable(3);
        factorialWithCallable(3);
        factorialWithRunnable(-1);
        factorialWithCallable(-1);
    }    
    
    static
void factorialWithRunnable(int n) { System.out.println("--- factorialWithRunnable ---"); final Integer[] result = new Integer[1]; Runnable task = () -> { result[0] = factorial(n); }; ExecutorService executorService = Executors.
newSingleThreadExecutor(); var future = executorService.submit(task); try { future.get(); System.out.println(MessageFormat.format("factorialWithRunnable result: {0}", result[0])); } catch (ExecutionException e) { System.out.println(e.getMessage()); } catch (InterruptedException interruptedException) { System.out.println(interruptedException.getMessage()); } executorService.shutdown(); } static void factorialWithCallable(int n) { System.out.println("--- factorialWithCallable ---"); Callable<Integer> task = () -> { return factorial(n); }; ExecutorService executorService = Executors.newSingleThreadExecutor(); var future = executorService.submit(task); try { var result = future.get().intValue(); System.out.println(MessageFormat.format("factorialWithCallable result: {0}", result)); } catch (ExecutionException e) { System.out.println(e.getMessage()); } catch (InterruptedException interruptedException) { System.out.println(interruptedException.getMessage()); } executorService.shutdown(); } static int factorial(int n) { if (n <= 0) { throw new IllegalArgumentException("Argument cannot be negative!"); } int r = 1; for (int i = 1; i <= n; i++) { r *= i; } return r; } }

以下是執行結果:

在這裡插入圖片描述
參考連結:
本文的原始碼
Java Runnable & Callable