回答:
用途の違いは何です
Runnable
とCallable
。違いがあるのは、戻りパラメータだけCallable
ですか?
基本的にはい。この質問への回答をご覧ください。そしてのjavadocCallable
。
Callable
そのすべてを行うことができる場合、両方を持つ必要性は何Runnable
ですか?
なぜなら、Runnable
インターフェースはすべてのことを行うことができないからですCallable
!
Runnable
はJava 1.0以降に存在しますがCallable
、Java 1.5でのみ導入されました... Runnable
サポートしていないユースケースを処理するためです。理論的には、JavaチームはRunnable.run()
メソッドのシグネチャを変更できた可能性がありますが、これにより、1.5より前のコードとのバイナリ互換性が失われ、古いJavaコードを新しいJVMに移行するときに再コーディングが必要になります。それは大きな違いです。Javaは下位互換性を保つように努めています...そして、これはJavaのビジネスコンピューティングにおける最大のセールスポイントの1つです。
そして、明らかに、タスクが結果を返したり、チェックされた例外をスローする必要がないユースケースがあります。これらのユースケースでRunnable
は、メソッドからCallable<Void>
ダミー(null
)値を使用して返すよりも、使用する方が簡潔ですcall()
。
Runnable
、下位互換性の理由から(大部分)存在することを示唆しています。しかしCallable
、インターフェースを(またはで)実装する(または要求する)ことが不必要または高すぎる状況はありませんScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
か?歴史が現在の結果を強制しなかったとしても、言語で両方のインターフェースを維持することには利点がないのですか?
Runnable
されたのではないかと思います。の「ボイラープレート」return null;
は弱い議論です。(少なくとも、それは私の決定だったでしょう...後方互換性を無視できる架空のコンテキストでは。)
Callable
を実装する必要がありますが、call()
メソッドを実装するRunnable
必要がありますrun()
。Callable
は値を返すことができますが、Runnable
できません。Callable
例外を確認投げることができますが、Runnable
できません。Aは、Callable
一緒に使用することができExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
た方法が、Runnable
することはできません。
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
私はこれをもう少しこれらの違いを説明できる別のブログで見つけました:
どちらのインターフェースも、異なる実行スレッドで実行したいクラスによって実装されますが、2つのインターフェースには次のような違いがあります。
Callable<V>
インスタンスタイプの結果を返しV
、一方、Runnable
インスタンスはありません。Callable<V>
インスタンスは、一方で、チェック例外をスローする可能性Runnable
のインスタンスができませんJavaの設計者は、Runnable
インターフェースの機能を拡張する必要性を感じていましたが、インターフェースの使用に影響を与えたくなかっRunnable
たためCallable
、Java 1.5で名前が付けられた別のインターフェースを使用するようになったのは、すでに変更されている理由です。既存のRunnable
。
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を呼び出すとすぐに、他のすべてのキューに入れられたアイテムが実行されるまでブロックする必要があります。その後、メソッドは値を返します。これは同期メカニズムです。
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
wherasオブジェクトは、チェック例外をスローすることはできませんCallable
オブジェクトが例外をスローすることができます。Runnable
インターフェースはJava 1.0以降Callable
に存在しましたが、Java 1.5でのみ導入されました。いくつかの類似点が含まれます
ExecutorServiceインターフェースのメソッドは次のとおりです。
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Oracleドキュメントからのこれらのインターフェースの目的:
Runnableインターフェースは、インスタンスがによって実行されることを目的とするクラスによって実装される必要がありますThread
。クラスは、という引数のないメソッドを定義する必要がありますrun
。
呼び出し可能:結果を返し、例外をスローするタスク。実装者は、callと呼ばれる引数のない単一のメソッドを定義します。Callable
インタフェースは同様であるRunnable
の両方がそのインスタンス潜在的に別のスレッドによって実行されるクラスのために設計されているという点で、。AはRunnable
、しかし、結果を返さないとチェック例外をスローすることはできません。
その他の違い:
を渡しRunnable
てThreadを作成できます。ただし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()
for Runnable
およびcall()
for Callable
。
ここですでに述べたように、Callableは比較的新しいインターフェースであり、並行性パッケージの一部として導入されました。CallableとRunnableの両方をエグゼキューターで使用できます。クラススレッド(Runnable自体を実装)は、Runnableのみをサポートします。
Runnableはエグゼキューターで引き続き使用できます。Callableの利点は、それをエグゼキューターに送信し、実行が完了すると更新されるFutureの結果をすぐに取得できることです。Runnableでも同じことが実装できますが、この場合は自分で結果を管理する必要があります。たとえば、すべての結果を保持する結果キューを作成できます。他のスレッドはこのキューで待機し、到着した結果を処理できます。
Future
か、すべての未処理の例外をキャッチするフックを使用または追加することにより、いくつかの作業を行う必要があります:docs.oracle.com/javase/6/docs/api/ java / lang /…
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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
たためCallable
、Java 1.5で名前が付けられた別のインターフェースを使用するようになったのは、すでに変更されている理由です。Runnable
Java 1.0以降、Javaの一部となっている既存のインターフェース。ソース
CallableとRunnableの違いは次のとおりです。
CallableとRunnableはどちらも類似しており、スレッドの実装に使用できます。Runnableを実装する場合はrun()メソッドを実装する必要がありますが、callableの場合はcall()メソッドを実装する必要があります。どちらの方法も同じように機能しますが、呼び出し可能なcall()メソッドの方が柔軟性があります。これらにはいくつかの違いがあります。
差のRunnableと呼び出し可能 below--として
1)runnableのrun()メソッドはvoidを返します。つまり、スレッドでさらに使用できるものをスレッドに返したい場合は、Runnable run()メソッドを使用できません。「Callable」という解決策があります。オブジェクトの形で何かを返したい場合は、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.0バージョンからのものですが、CallableはExecuterフレームワークを備えたJava 1.5バージョンからのものです。
Executersに慣れている場合は、RunnableではなくCallableを使用する必要があります。
ご理解いただければ幸いです。
Runnable(vs)Callableは、Executerフレームワークを使用しているときにポイントになります。
ExecutorServiceはのサブExecutor
インターフェースであり、RunnableタスクとCallableタスクの両方を受け入れます。
以前のマルチスレッディングは、Interface 1.0以降を使用して実現できますが、ここで問題となるのは、スレッドタスクを完了した後、スレッド情報を収集できないことです。データを収集するために、静的フィールドを使用する場合があります。Runnable
例各生徒のデータを収集するための個別のスレッド。
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() );
}
この問題を解決するために、結果を返し、例外をスローする1.5以降のバージョンを導入しました。Callable<V>
単一の抽象メソッド: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<?>
、future.get()submit(Runnable):Future<?>
を使用している場合、新しいスレッドを作成し、メインスレッドをブロックします。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();
}
}
関数型プログラミングと一致する一種のインターフェース命名規則です
//Runnable
interface Runnable {
void run();
}
//Action - throws exception
interface Action {
void run() throws Exception;
}
//Consumer - consumes a value/values, throws exception
interface Consumer1<T> {
void accept(T t) throws Exception;
}
//Callable - return result, throws exception
interface Callable<R> {
R call() throws Exception;
}
//Supplier - returns result, throws exception
interface Supplier<R> {
R get() throws Exception;
}
//Predicate - consumes a value/values, returns true or false, throws exception
interface Predicate1<T> {
boolean test(T t) throws Exception;
}
//Function - consumes a value/values, returns result, throws exception
public interface Function1<T, R> {
R apply(T t) throws Throwable;
}
...