Runnable
Java で並行スレッドを設計する際にとCallable
インターフェースを使用することの違いは何ですか?
14 に答える
ここで説明を参照してください。
Callable インターフェースは Runnable と似ており、どちらもインスタンスが別のスレッドによって実行される可能性があるクラス用に設計されています。ただし、Runnable は結果を返さず、チェック例外をスローできません。
Runnable
とのアプリケーションの違いは何ですかCallable
。に存在する戻りパラメータとの違いのみCallable
ですか?
基本的に、はい。この質問への回答を参照してください。そしてのjavadocCallable
。
Callable
それがすべてできるのなら、両方を持つ必要は何Runnable
ですか?
Runnable
インターフェイスはすべてを実行できるわけではないためCallable
です。
Runnable
は Java 1.0 から存在していますがCallable
、Java 1.5 でのみ導入されました ...Runnable
サポートされていないユースケースを処理するためです。理論的には、Java チームはメソッドの署名を変更できたかもしれませんがRunnable.run()
、これにより 1.5 より前のコードとのバイナリ互換性が失われ、古い Java コードを新しい JVM に移行するときに再コーディングが必要になります。それはBIG NO-NOです。Java は下位互換性を保つよう努めています...そしてそれは、ビジネス コンピューティングにおける Java の最大のセールス ポイントの 1 つです。
そして、明らかに、タスクが結果を返したり、チェック済みの例外をスローしたりする必要がないユースケースがあります。これらのユースケースでは、メソッドからダミーの ( ) 値を使用して返すRunnable
よりも、使用する方が簡潔です。Callable<Void>
null
call()
これらの違いをもう少し説明できる別のブログでこれを見つけました:
どちらのインターフェースも、別の実行スレッドで実行したいクラスによって実装されていますが、2 つのインターフェースには次のような違いがほとんどありません。
- インスタンスは typeの
Callable<V>
結果を返しますが、インスタンスは返しV
ませRunnable
ん。 Callable<V>
インスタンスはチェック済み例外をスローする場合がありますが、インスタンスRunnable
はできません。
Java の設計者は、インターフェイスの機能を拡張する必要性を感じていましたが、Runnable
インターフェイスの使用に影響を与えたくありませんでした。おそらくそれが、既存のインターフェイスを変更するよりも、Java 1.5 で名前をRunnable
付けた別のインターフェイスを持つことにした理由です。Callable
既存のRunnable
。
Runnable と Callable を使用する場所を見てみましょう。
Runnable と Callable はどちらも、呼び出しスレッドとは異なるスレッドで実行されます。ただし、Callable は値を返すことができますが、Runnable はできません。では、これが実際に適用されるのはどこでしょうか。
Runnable : ファイア アンド フォーゲット タスクがある場合は、Runnable を使用します。コードを Runnable 内に配置し、run() メソッドが呼び出されると、タスクを実行できます。タスクを実行するとき、呼び出しスレッドは実際には気にしません。
Callable : タスクから値を取得しようとしている場合は、Callable を使用します。Callable だけでは機能しません。Callable をラップして future.get () で値を取得する Future が必要になります。ここでは、Future が結果を返して Callable の call() メソッドの実行を待機するまで、呼び出しスレッドはブロックされます。
Runnable と Callable の両方のラップされたメソッドが定義されているターゲット クラスへのインターフェイスについて考えてみてください。呼び出しクラスは、どれが Runnable でどれが Callable であるかを知らずに、インターフェイス メソッドをランダムに呼び出します。Runnable メソッドは、Callable メソッドが呼び出されるまで非同期で実行されます。ここでは、ターゲット クラスから値を取得しているため、呼び出し元のクラスのスレッドがブロックされます。
注 : ターゲット クラス内では、Callable と Runnable を単一のスレッド エグゼキューターで呼び出すことができ、このメカニズムをシリアル ディスパッチ キューに似たものにします。したがって、呼び出し元が Runnable でラップされたメソッドを呼び出す限り、呼び出し元のスレッドはブロックされることなく非常に高速に実行されます。Future メソッドでラップされた Callable を呼び出すとすぐに、キューに入れられた他のすべての項目が実行されるまでブロックする必要があります。その場合にのみ、メソッドは値を返します。これは同期メカニズムです。
Callable
インターフェイスcall()
はメソッドを宣言し、オブジェクト 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
一方run()
、実行可能なスレッドを作成し、その上で start() を呼び出すときに呼び出されるメソッドを宣言するインターフェイスです。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();
}
いくつかの注目すべき違いを要約すると、
Runnable
オブジェクトは結果を返しませんが、オブジェクトCallable
は結果を返します。- オブジェクトは例外をスローできますが、オブジェクトは
Runnable
チェック例外をスローできませんCallable
。 - この
Runnable
インターフェースは Java 1.0 から存在していますがCallable
、Java 1.5 でのみ導入されました。
いくつかの類似点が含まれます
- Runnable または Callable インターフェースを実装するクラスのインスタンスは、別のスレッドによって実行される可能性があります。
- Callable および Runnable インターフェースの両方のインスタンスは、submit() メソッドを介して ExecutorService によって実行できます。
- どちらも関数型インターフェースであり、Java8 以降の Lambda 式で使用できます。
ExecutorService インターフェイスのメソッドは
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Oracleドキュメントからのこれらのインタフェースの目的:
実行可能なインターフェイスは、インスタンスがThread
. クラスは、 と呼ばれる引数のないメソッドを定義する必要がありますrun
。
Callable : 結果を返し、例外をスローする可能性があるタスク。実装者は、call という引数のない単一のメソッドを定義します。インタフェースは、インスタンスが別のスレッドによって実行される可能性のあるクラス用に設計されているという点で に似Callable
ています。Runnable
ただし、 ARunnable
は結果を返さず、チェック例外をスローできません。
その他の違い:
Thread
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(); } }
Runnable
ファイア アンド フォーゲット コールに使用します。Callable
結果を確認するために使用します。Callable
とは異なり、 invokeAllメソッドに渡すことができますRunnable
。メソッドinvokeAny
をinvokeAll
使用して、最も一般的に役立つ形式の一括実行を実行します。タスクのコレクションを実行してから、少なくとも 1 つまたはすべてのタスクが完了するのを待ちます。些細な違い: 実装するメソッド名 =>
run()
forRunnable
とcall()
forCallable
.
ここですでに述べたように、Callableは比較的新しいインターフェースであり、並行性パッケージの一部として導入されました。CallableとRunnableの両方をエグゼキュータで使用できます。クラススレッド(Runnable自体を実装する)はRunnableのみをサポートします。
Runnableは引き続きエグゼキュータで使用できます。Callableの利点は、エグゼキュータに送信して、実行が終了したときに更新される将来の結果をすぐに返すことができることです。Runnableでも同じことが実装できますが、この場合、結果を自分で管理する必要があります。たとえば、すべての結果を保持する結果キューを作成できます。他のスレッドはこのキューで待機し、到着した結果を処理できます。