web-dev-qa-db-ja.com

JavaのRunnableインターフェイスとCallableインターフェイスの違い

Javaで並行スレッドを設計するときにRunnableインターフェースとCallableインターフェースを使用することの違いは何ですか?なぜ、どちらを選択するのですか?

450
Scottm

説明 はこちら をご覧ください。

CallableインタフェースはRunnableと似ていますが、どちらもインスタンスが別のスレッドによって実行される可能性があるクラス用に設計されています。 ただし、Runnableは結果を返さず、チェック済み例外をスローすることはできません。

407
Jorge Ferreira

RunnableCallableのアプリケーションの違いは何ですか。違いはCallableに存在するreturnパラメータとの違いだけですか?

基本的には、そうです。 この質問 の答えを見てください。そして javadoc for Callable

CallableRunnableができることすべてを実行できる場合、両方を持つ必要がありますか?

RunnableインターフェースCallableが行うことすべてを行うことができないため、できません。

RunnableはJava 1.0から登場しましたが、CallableはJava 1.5でのみ導入されました... Runnableがサポートしないユースケースを処理するために。理論的には、JavaチームはRunnable.run()メソッドのシグネチャを変更できたかもしれませんが、これは1.5より前のコードとのバイナリ互換性を壊し、古いJavaコードを新しいJVMに移行するときに再コーディングを必要とします。それは大きなNOです。 Javaは後方互換性を保つように努力しています...そしてそれはビジネスコンピューティングのためのJavaの最大のセールスポイントの1つでした。

そして、明らかに、タスクがneedで結果を返さなかったり、チェックされた例外を投げたりしないユースケースがあります。そのようなユースケースでは、Runnableを使用する方がCallable<Void>を使用してcall()メソッドからダミー(null)値を返すよりも簡潔です。

245
Stephen C
  • Callablecall()メソッドを実装する必要がありますが、Runnablerun()メソッドを実装する必要があります。
  • Callableは値を返すことができますが、Runnableは返すことができません。
  • Callableはチェック例外をスローできますが、Runnableはスローできません。
  • CallableExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)メソッドで使用できますが、Runnableは使用できません。

    public interface Runnable {
        void run();
    }
    
    public interface Callable<V> {
        V call() throws Exception;
    }
    
77
nikli

私はこれをもう少し詳しく説明できる別のブログで見つけました 違い

どちらのインターフェースも異なる実行スレッドで実行したいクラスによって実装されていますが、2つのインターフェースには次のような違いはほとんどありません。

  • Callable<V>インスタンスはV型の結果を返しますが、Runnableインスタンスは返しません。
  • Callable<V>インスタンスはチェックされた例外を投げますが、Runnableインスタンスは投げません。

Javaの設計者はRunnableインターフェースの機能を拡張する必要性を感じましたが、彼らはRunnableインターフェースの使用に影響を与えたくなかったので、おそらくJava 1.5ではCallableという名前のインターフェースを別に選んだ理由既存のRunnableを変更します。

36
amoran

RunnableとCallableをどこで使うのか見てみましょう。

RunnableとCallableはどちらも呼び出し元のスレッドとは異なるスレッドで実行されます。しかし、Callableは値を返すことができ、Runnableは返すことができません。それで、これは本当にどこにあてはまりますか。

Runnable:発火して忘れた場合はRunnableを使用してください。あなたのコードをRunnableの中に入れて、run()メソッドが呼ばれたとき、あなたはあなたのタスクを実行することができます。あなたがあなたのタスクを実行するとき、呼び出し側のスレッドは本当に気にしません。

Callable:タスクから値を取得しようとしているなら、Callableを使います。今それ自身で呼出し可能は仕事をしないでしょう。あなたはあなたのCallableを包み込み、future.get()であなたの値を得るFutureが必要になるでしょう。ここで呼び出しスレッドはFutureが戻ってくるまでブロックされ、結果はCallableのcall()メソッドが実行されるのを待っています。

それで、RunnableとCallableの両方のラップされたメソッドが定義されているターゲットクラスへのインターフェースについて考えてください。呼び出し側クラスは、どちらがRunnableでどれがCallableであるかを知らずに、ランダムにあなたのインターフェースメソッドを呼び出します。 Runnableメソッドは、Callableメソッドが呼び出されるまで非同期に実行されます。ターゲットクラスから値を取得しているので、呼び出し元のクラスのスレッドはブロックされます。

注:ターゲットクラスの内部では、シングルスレッドエグゼキュータ上でCallableとRunnableを呼び出すことができ、このメカニズムはシリアルディスパッチキューに似ています。つまり、呼び出し側があなたのRunnableラップされたメソッドを呼び出す限り、呼び出し側のスレッドはブロックせずに本当に速く実行されます。 FutureメソッドでラップされたCallableを呼び出すとすぐに、他のすべてのキュー項目が実行されるまでブロックする必要があります。そのとき初めて、メソッドは値を返します。これは同期メカニズムです。

26

Callableインターフェースはcall()メソッドを宣言しており、Objectの型としてジェネリックを提供する必要がありますcall()が返すべきです -

public interface Callable<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を使ってThreadを作成し、それにstart()を呼び出すときに呼び出されるrun()メソッドを宣言するインターフェースです。 run()を直接呼び出すこともできますが、run()メソッドを実行するのは同じスレッドです。

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used 
     * to create a thread, starting the thread causes the object's 
     * <code>run</code> method to be called in that separately executing 
     * thread. 
     * <p>
     * The general contract of the method <code>run</code> is that it may 
     * take any action whatsoever.
     *
     * @see     Java.lang.Thread#run()
     */
    public abstract void run();
}

いくつかの注目すべき違いを要約すると、

  1. Runnableオブジェクトは結果を返しませんが、Callableオブジェクトは結果を返します。
  2. Runnableオブジェクトは、チェック済み例外をスローできません。ただし、Callableオブジェクトは、例外をスローできます。
  3. RunnableインターフェースはJava 1.0から登場しましたが、CallableはJava 1.5でのみ導入されました。

類似点はほとんどありません

  1. RunnableまたはCallableインタフェースを実装するクラスのインスタンスは、他のスレッドによって実行される可能性があります。
  2. CallableおよびRunnableインターフェースのインスタンスは、submit()メソッドを介してExecutorServiceによって実行できます。
  3. どちらも機能的なインターフェースであり、Java 8以降のLambda式で使用できます。

ExecutorServiceインターフェースのメソッドは

<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
14
Aniket Thakur

Oracleのマニュアルに記載されているこれらのインタフェースの目的

Runnable インタフェースは、そのインスタンスがThreadによって実行されることを意図しているすべてのクラスによって実装されるべきです。クラスはrunと呼ばれる引数のないメソッドを定義しなければなりません。

呼び出し可能 :結果を返し、例外をスローする可能性があるタスク。実装者は、callと呼ばれる引数なしで単一のメソッドを定義します。 Callableインターフェースは、インスタンスが別のスレッドによって実行される可能性があるクラス用に設計されているという点でRunnableと似ています。ただし、Runnableは結果を返さず、チェック済み例外をスローすることもできません。

その他の違い

  1. スレッド を作成するためにRunnableを渡すことができます。しかし、パラメータとしてCallableを渡して新しいスレッドを作成することはできません。 CallableはExecutorServiceインスタンスにのみ渡すことができます。

    例:

    public class HelloRunnable implements Runnable {
    
        public void run() {
            System.out.println("Hello from a thread!");
        }   
    
        public static void main(String args[]) {
            (new Thread(new HelloRunnable())).start();
        }
    
    }
    
  2. Runnableを発砲に使用し、呼び出しを忘れてください。結果を検証するにはCallableを使用してください。

  3. Callableは、Runnableとは異なり、 invokeAll メソッドに渡すことができます。メソッドinvokeAnyおよびinvokeAllは、最も一般的に有用な形式の一括実行を実行し、一連のタスクを実行してから、少なくとも1つまたはすべてが完了するのを待ちます。

  4. ちょっとした違い:実装するメソッド名=> Runnableの場合はrun()Callableの場合はcall()

14
Ravindra babu

すでに述べたように、Callableは比較的新しいインターフェースであり、並行処理パッケージの一部として導入されました。 CallableとRunnableはどちらもexecutorで使用できます。 Threadクラス(Runnable自体を実装する)は、Runnableのみをサポートします。

Runnableをエクゼキュータと共に使用することはできます。 Callableの利点は、実行プログラムに送信してすぐに元に戻すことができるということです。これは、実行が完了すると更新されます。同じことがRunnableで実装されるかもしれません、しかしこの場合あなたは結果をあなた自身で管理しなければなりません。たとえば、すべての結果を保持する結果キューを作成できます。他のスレッドはこのキューで待機し、到着した結果を処理できます。

11
AlexR
+-------------------------------------+--------------------------------------------------------------------------------------------------+
|              Runnable               |                                           Callable<T>                                            |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| Introduced in Java 1.0 of Java.lang | Introduced in Java 1.5 of Java.util.concurrent library                                           |
| Runnable cannot be parametrized     | Callable is a parametrized type whose type parameter indicates the return type of its run method |
| Runnable has run() method           | Callable has call() method                                                                       |
| Runnable.run() returns void         | Callable.call() returns a value of Type T                                                        |
| Can not throw Checked Exceptions    | Can throw Checked Exceptions                                                                     |
+-------------------------------------+--------------------------------------------------------------------------------------------------+

Javaの設計者はRunnableインターフェースの機能を拡張する必要性を感じましたが、彼らはRunnableインターフェースの使用には影響を与えたくなかったので、おそらくJava 1.5でCallableという名前のインターフェースを別に選んだ理由です。 Java 1.0以降Javaの一部であった既存のRunnableインタフェースを変更する。 ソース

6
Premraj

CallableとRunnableの違いは次のとおりです。

  1. CallableはJDK 5.0で導入されましたが、RunnableはJDK 1.0で導入されました
  2. Callableにはcall()メソッドがありますが、Runnableにはrun()メソッドがあります。
  3. Callableには値を返すcallメソッドがありますが、Runnableには値を返さないrunメソッドがあります。
  4. callメソッドはチェック済み例外をスローできますが、runメソッドはチェック済み例外をスローできません。
  5. タスクキューに入れるにはsubmit()メソッドを呼び出しますが、タスクキューに入れるにはexecute()メソッドを使います。
5
Raman Gupta

CallableとRunnableの両方は互いに似ており、スレッドの実装に使用できます。 Runnableを実装する場合はrun()メソッドを実装する必要がありますが、呼び出し可能の場合はcall()メソッド、両方のメソッドを実装する必要があります同様の方法で動作しますが、呼び出し可能call()メソッドには柔軟性があります。それらにはいくつかの違いがあります。

Runnablecallableの違いは以下のとおりです-

1)run()runnableのメソッドはvoidを返します。つまり、スレッドが何かを返したい場合は、さらに使用できるものを返します- Runnable run()での選択なしメソッド。解決策があります'Callable'objectの形式で何かを返したい場合、Runnableの代わりにCallableを使用する必要があります。呼び出し可能なインターフェイスには、メソッド'Object()を返すcall()'があります。

メソッドシグネチャ-Runnable->

public void run(){}

呼び出し可能->

public Object call(){}

2)Runnable run()メソッドの場合、チェックされた例外が発生した場合、try catchブロックで処理する必要があります、ただしCallable callの場合()メソッドチェック済み例外をスローできます以下のように

 public Object call() throws Exception {}

3)Runnableはレガシーから来ていますJava 1.バージョンですが、callableJava 1.5実行者フレームワーク。

Executersに精通している場合は、RunnableではなくCallableを使用にする必要があります。

ご理解ください。

3
Sudhakar Pandey

Runnable(vs)Callableは、Executerフレームワークを使用しているときに有効になります。

ExecutorServiceは、 Executor のサブインターフェースで、RunnableタスクとCallableタスクの両方を受け入れます。

以前のマルチスレッドは、InterfaceRunnableを使って実現できます。1.0以降しかし、ここで問題はスレッドタスクを完了した後に我々はスレッド情報を収集することができないということです。データを収集するために、静的フィールドを使用することができます。

例各生徒データを収集するために別々のスレッドを作成します。

static HashMap<String, List> multiTasksData = new HashMap();
public static void main(String[] args) {
    Thread t1 = new Thread( new RunnableImpl(1), "T1" );
    Thread t2 = new Thread( new RunnableImpl(2), "T2" );
    Thread t3 = new Thread( new RunnableImpl(3), "T3" );

    multiTasksData.put("T1", new ArrayList() ); // later get the value and update it.
    multiTasksData.put("T2", new ArrayList() );
    multiTasksData.put("T3", new ArrayList() );
}

この問題を解決するために彼らは導入しましたCallable<V>1.5以降 これは結果を返し、例外を投げます。

  • 単一の抽象メソッド:CallableおよびRunnableインターフェースはどちらも単一の抽象メソッドを持っています。つまり、それらはJava 8のラムダ式で使用できます。

    public interface Runnable {
    public void run();
    }
    
    public interface Callable<Object> {
        public Object call() throws Exception;
    }
    

実行用タスクを ExecutorService に委任する方法はいくつかあります。

  • このメソッドはvoidを返すため、execute(Runnable task):voidは新しいスレッドを生成しますが、メインスレッドや呼び出し元のスレッドはブロックしません。
  • future.get()を使用している場合、submit(Callable<?>):Future<?>submit(Runnable):Future<?>は新しいスレッドを作成し、メインスレッドをブロックします。

Runnable、Executorフレームワークで呼び出し可能なインタフェースの使用例。

class CallableTask implements Callable<Integer> {
    private int num = 0;
    public CallableTask(int num) {
        this.num = num;
    }
    @Override
    public Integer call() throws Exception {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < 5; i++) {
            System.out.println(i + " : " + threadName + " : " + num);
            num = num + i;
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task. Final Value : "+ num);

        return num;
    }
}
class RunnableTask implements Runnable {
    private int num = 0;
    public RunnableTask(int num) {
        this.num = num;
    }
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < 5; i++) {
            System.out.println(i + " : " + threadName + " : " + num);
            num = num + i;
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task. Final Value : "+ num);
    }
}
public class MainThread_Wait_TillWorkerThreadsComplete {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("Main Thread start...");
        Instant start = Java.time.Instant.now();

        runnableThreads();
        callableThreads();

        Instant end = Java.time.Instant.now();
        Duration between = Java.time.Duration.between(start, end);
        System.out.format("Time taken : %02d:%02d.%04d \n", between.toMinutes(), between.getSeconds(), between.toMillis()); 

        System.out.println("Main Thread completed...");
    }
    public static void runnableThreads() throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<?> f1 = executor.submit( new RunnableTask(5) );
        Future<?> f2 = executor.submit( new RunnableTask(2) );
        Future<?> f3 = executor.submit( new RunnableTask(1) );

        // Waits until pool-thread complete, return null upon successful completion.
        System.out.println("F1 : "+ f1.get());
        System.out.println("F2 : "+ f2.get());
        System.out.println("F3 : "+ f3.get());

        executor.shutdown();
    }
    public static void callableThreads() throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<Integer> f1 = executor.submit( new CallableTask(5) );
        Future<Integer> f2 = executor.submit( new CallableTask(2) );
        Future<Integer> f3 = executor.submit( new CallableTask(1) );

        // Waits until pool-thread complete, returns the result.
        System.out.println("F1 : "+ f1.get());
        System.out.println("F2 : "+ f2.get());
        System.out.println("F3 : "+ f3.get());

        executor.shutdown();
    }
}
0
Yash