JavaのRunnableインターフェースとCallableインターフェースの違い
-
02-07-2019 - |
質問
Javaで並行スレッドを設計する際にRunnable
とCallable
インターフェースを使用することの違いは何ですか、なぜ一方を選択するのですか?
解決
こちらの説明を参照してください。
Callableインターフェースは 両方が設計されている点で、実行可能 インスタンスが 別の人によって実行される可能性がある 糸。 ただし、Runnableは 結果を返し、スローできません チェック例外。
他のヒント
Runnable
とCallable
のアプリケーションの違いは何ですか。Runnable.run()
に存在する戻りパラメーターとの違いだけですか?
基本的にははい。 この質問の回答をご覧ください。また、 Callable<Void>
のjavadoc 。
null
がcall()
のすべてを実行できる場合、両方を持つ必要がありますか?
<=>インターフェースはが行うすべてをできないためです!
<=>はJava 1.0から存在しますが、<=>はJava 1.5でのみ導入されました... <=>がサポートしないユースケースを処理するために。理論的には、Javaチームは<=>メソッドのシグネチャを変更できましたが、これにより1.5以前のコードとのバイナリ互換性が壊れ、古いJavaコードを新しいJVMに移行するときに再コーディングが必要になりました。それは大きなノーです。 Javaは下位互換性を保つように努めています...それはビジネスコンピューティングのJavaの最大のセールスポイントの1つです。
そして、明らかに、タスクが結果を返したりチェック例外をスローしたりする必要がない ユースケースがあります。これらのユースケースでは、<=>を使用して<=>メソッドからダミー(<=>)値を返すよりも<=>を使用する方が簡潔です。
- A
Callable
はcall()
メソッドを実装する必要があり、Runnable
はrun()
メソッドを実装する必要があります。 -
ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
は値を返すことができますが、<=>は返すことができません。 - <=>はチェック済み例外をスローできますが、<=>はスローできません。
-
<=>は<=>メソッドで使用できますが、<=>は使用できません。
public interface Runnable { void run(); } public interface Callable<V> { V call() throws Exception; }
このことについてもう少し説明できる別のブログでこれを見つけました違い:
両方のインターフェースは異なる実行スレッドで実行したいクラスによって実装されますが、2つのインターフェースの違いはほとんどありません:
-
Callable<V>
インスタンスはV
型の結果を返しますが、Runnable
インスタンスは返しません。 -
Callable
インスタンスはチェック済み例外をスローできますが、<=>インスタンスはスローできません
Javaの設計者は、<=>インターフェースの機能を拡張する必要性を感じていましたが、<=>インターフェースの使用に影響を与えたくなかったため、おそらく別の既存の<=>を変更するよりも、Java 1.5では<=>という名前のインターフェース。
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()
メソッドを宣言し、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();
}
いくつかの注目すべき違いをまとめると
- <=>オブジェクトは結果を返しませんが、<=>オブジェクトは結果を返します。
- <=>オブジェクトはチェック例外をスローできませんが、<=>オブジェクトは 例外。
- <=>インターフェースのみが導入されたのに対し、<=>インターフェースはJava 1.0以来存在していました。 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ドキュメントのこれらのインターフェイスの目的:
Runnable インターフェースを実装する必要がありますインスタンスがThread
によって実行されることが意図されているクラスによって。クラスは、引数なしのrun
と呼ばれるメソッドを定義する必要があります。
呼び出し可能:A結果を返し、例外をスローする可能性のあるタスク。実装者は、callと呼ばれる引数なしで単一のメソッドを定義します。
Callable
インターフェースは、インスタンスが別のスレッドによって実行される可能性のあるクラス用に設計されているという点で、Runnable
と似ています。ただし、ExecutorService
は結果を返さず、チェック済み例外をスローできません。
その他の違い:
-
invokeAny
を渡して、スレッド。ただし、パラメータとしてinvokeAll
を渡して新しいスレッドを作成することはできません。 Callableはrun()
インスタンスにのみ渡すことができます。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(); } }
-
発砲と忘却の呼び出しには
call()
を使用します。 <=>を使用して結果を確認します。 -
<=>は invokeAll メソッドは<=>とは異なります。メソッド<=>および<=>は、最も一般的に有用な形式の一括実行を実行し、タスクのコレクションを実行し、少なくとも1つまたはすべてが完了するのを待機します
-
わずかな違い:実装するメソッド名= <!> gt; <=>の場合は<=>および<=>の場合は<=>。
ここで既に述べたように、Callableは比較的新しいインターフェースであり、同時実行パッケージの一部として導入されました。 CallableとRunnableの両方をエグゼキューターで使用できます。クラススレッド(Runnable自体を実装する)はRunnableのみをサポートします。
エグゼキューターでRunnableを引き続き使用できます。 Callableの利点は、それをexecutorに送信し、実行が終了すると更新されるFuture結果をすぐに取得できることです。 Runnableでも同じことが実装できますが、この場合、結果を自分で管理する必要があります。たとえば、すべての結果を保持する結果キューを作成できます。他のスレッドはこのキューで待機し、到着した結果を処理できます。
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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
インターフェースの機能を拡張する必要性を感じていましたが、Callable
インターフェースの使用に影響を与えたくなかったため、おそらく別のJava 1.0からJavaの一部である既存の<=>インターフェイスを変更するよりも、Java 1.5で<=>という名前のインターフェイス。 ソース
CallableとRunnableの違いは次のとおりです。
- CallableはJDK 5.0で導入されましたが、RunnableはJDK 1.0で導入されました
- Callableにはcall()メソッドがありますが、Runnableにはrun()メソッドがあります。
- Callableには値を返すcallメソッドがありますが、Runnableには値を返さないrunメソッドがあります。
- callメソッドはチェック済み例外をスローできますが、runメソッドはチェック済み例外をスローできません。
- Callableはsubmit()メソッドを使用してタスクキューに入れますが、Runnableはexecute()メソッドを使用してタスクキューに入れます。
Callableと Runnable はどちらも互いに似ており、スレッドの実装に使用できます。 Runnable を実装する場合は run()メソッドを実装する必要がありますが、callableの場合は call()メソッドを実装する必要があり、両方のメソッド同様の方法で機能しますが、呼び出し可能な call()メソッドには柔軟性があります。それらにはいくつかの違いがあります。
以下のように Runnable と callable の違い-
1) runnable の run()メソッドは void を返します。つまり、スレッドが何かを返したい場合は、さらに使用できるものを返します Runnable run()メソッドを選択する必要はありません。 「Callable」という解決策があります。オブジェクトの形で何かを返したい場合は、 RunnableではなくCallableを使用する必要があります。呼び出し可能インターフェイスには、オブジェクトを返すメソッド 'call()' があります。
メソッドのシグネチャ- Runnable-<!> gt;
public void run(){}
Callable-<!> gt;
public Object call(){}
2) Runnable run()メソッドの場合、チェックされた例外が発生した場合、 try catchブロックで処理する必要がある必要がありますが、以下のように、チェック済み例外をスローできるメソッドを呼び出し可能call()
public Object call() throws Exception {}
3) Runnable は従来の java 1.0 バージョンから来ましたが、 callable は Java 1.5 バージョンから< strong> Executer フレームワーク。
実行者に慣れている場合は、 RunnableではなくCallableを使用する必要があります。
ご理解ください。
Runnable(vs)Callable は、Executerフレームワークを使用しているときに重要になります。
ExecutorServiceは、 Executor
のサブインターフェースです。 strong> 。RunnableタスクとCallableタスクの両方を受け入れます。
以前のマルチスレッドは、インターフェイス Runnable
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 <に委任する方法はいくつかあります。
-
execute(Runnable task):void
このメソッドはvoidを返すため、新しいスレッドを作成しますが、メインスレッドまたは呼び出し元スレッドをブロックしません。 -
submit(Callable<?>):Future<?>
、submit(Runnable):Future<?>
は、 future.get()を使用している場合、新しいスレッドを作成し、メインスレッドをブロックします。
ExecutorフレームワークでインターフェイスRunnable、Callableを使用する例。
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();
}
}