Was ist der Unterschied zwischen den Runnable
- und Callable
-Schnittstellen, wenn Sie einen gleichzeitigen Thread in Java entwerfen.
Siehe Erklärung hier .
Die Callable-Schnittstelle ist ähnlich wie Runable, in dem beide entworfen werden für Klassen, deren Instanzen .__ sind. möglicherweise von einem anderen ausgeführt Faden. A Runable kann jedoch nicht Gibt ein Ergebnis zurück und kann keine .__ werfen. geprüfte Ausnahme.
Was sind die Unterschiede in den Anwendungen von
Runnable
undCallable
. Ist der Unterschied nur mit dem Rückgabeparameter inCallable
vorhanden?
Grundsätzlich ja. Siehe die Antworten auf diese Frage . Und das javadoc für Callable
.
Was ist die Notwendigkeit, beides zu haben, wenn
Callable
all das kann, wasRunnable
kann?
Weil die Runnable
Schnittstelle nicht alles kann , was Callable
macht!
Runnable
gibt es seit Java 1.0, aber Callable
wurde nur in Java 1.5 eingeführt ... um Anwendungsfälle zu behandeln, die Runnable
unterstützt nicht. Theoretisch hätte das Java -Team die Signatur der Runnable.run()
-Methode ändern können, dies hätte jedoch die Binärkompatibilität mit Code vor 1.5 unterbrochen und eine Neucodierung bei der Migration alter Javaerforderlich gemacht. _ Code für neuere JVMs. Das ist ein großes Nein-Nein. Java ist bestrebt, abwärtskompatibel zu sein ... und das war eines der größten Verkaufsargumente von Java für Business Computing.
Und natürlich gibt es Anwendungsfälle, in denen eine Aufgabe nicht ein Ergebnis zurückgeben oder eine aktivierte Ausnahme auslösen muss . In diesen Anwendungsfällen ist die Verwendung von Runnable
präziser als die Verwendung von Callable<Void>
und die Rückgabe eines Dummy-Werts (null
) von der Methode call()
.
Callable
muss die call()
-Methode implementieren, während ein Runnable
die run()
-Methode implementieren muss.Callable
kann einen Wert zurückgeben, ein Runnable
jedoch nicht.Callable
kann eine geprüfte Ausnahme auslösen, eine Runnable
jedoch nicht.Ein Callable
kann mit ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
-Methoden verwendet werden, ein Runnable
jedoch nicht.
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
Ich habe dies in einem anderen Blog gefunden, das es ein bisschen mehr erklären kann Unterschiede :
Beide Schnittstellen werden zwar von den Klassen implementiert, die in einem anderen Ausführungsthread ausgeführt werden sollen, es gibt jedoch nur wenige Unterschiede zwischen den beiden Schnittstellen:
Callable<V>
-Instanz gibt ein Ergebnis des Typs V
zurück, eine Runnable
-Instanz jedoch nicht.Callable<V>
-Instanz kann geprüfte Ausnahmen auslösen, eine Runnable
-Instanz jedoch nichtDie Entwickler von Java hatten das Bedürfnis, die Fähigkeiten der Runnable
-Schnittstelle zu erweitern, wollten jedoch die Verwendung der Runnable
-Schnittstelle nicht beeinträchtigen. Dies war wahrscheinlich der Grund, warum sie in Java 1.5 eine separate Schnittstelle namens Callable
hatten Ändern der bereits vorhandenen Runnable
.
Schauen wir uns an, wo man Runnable und Callable verwenden würde.
Runable und Callable laufen beide in einem anderen Thread als der aufrufende Thread. Callable kann jedoch einen Wert zurückgeben und Runnable nicht. Wo gilt das wirklich?.
Runable : Wenn Sie eine Feuer- und Vergessensaufgabe haben, verwenden Sie Runable. Fügen Sie Ihren Code in ein Runable ein. Wenn die run () -Methode aufgerufen wird, können Sie Ihre Aufgabe ausführen. Dem aufrufenden Thread ist es wirklich egal, wann Sie Ihre Aufgabe ausführen.
Callable : Wenn Sie versuchen, einen Wert von einer Aufgabe abzurufen, verwenden Sie Callable. Jetzt aufrufbar alleine wird die Arbeit nicht machen. Sie benötigen eine Zukunft, die Sie um Ihren Callable wickeln und Ihre Werte in future.get () erhalten. Hier wird der aufrufende Thread blockiert, bis die Zukunft mit Ergebnissen zurückkommt, die wiederum darauf warten, dass die Call () - Methode von Callable ausgeführt wird.
Stellen Sie sich also eine Schnittstelle zu einer Zielklasse vor, in der Sie sowohl ausführbare als auch aufrufbare Methoden definiert haben. Die aufrufende Klasse ruft Ihre Schnittstellenmethoden nach dem Zufallsprinzip auf, ohne zu wissen, welche ausführbar und welche aufrufbar sind. Die Runable-Methoden werden asynchron ausgeführt, bis eine Callable-Methode aufgerufen wird. Hier blockiert der Thread der aufrufenden Klasse, da Sie Werte von Ihrer Zielklasse abrufen.
ANMERKUNG: Innerhalb Ihrer Zielklasse können Sie die Aufrufe von Callable und Runnable auf einem einzelnen Thread-Executor ausführen, wodurch dieser Mechanismus einer seriellen Versandwarteschlange ähnelt. Solange der Aufrufer Ihre Runnable-Wrapped-Methoden aufruft, wird der aufrufende Thread sehr schnell ausgeführt, ohne zu blockieren. Sobald eine in Future-Methode umhüllte Callable aufgerufen wird, muss sie blockiert werden, bis alle anderen Elemente in der Warteschlange ausgeführt werden. Nur dann wird die Methode mit Werten zurückgegeben. Dies ist ein Synchronisationsmechanismus.
Callable
interface deklariert die call()
-Methode, und Sie müssen Generics angeben, wenn Objekttyp () aufgerufen werden soll.
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
ist dagegen eine Schnittstelle, die die run()
-Methode deklariert, die aufgerufen wird, wenn Sie einen Thread mit dem ausführbaren Befehl erstellen und den Befehl start () aufrufen. Sie können run () auch direkt aufrufen, aber die run () -Methode führt einfach den gleichen Thread aus.
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();
}
Zusammenfassend sind einige bemerkenswerte Unterschiede zu nennen
Runnable
-Objekt gibt kein Ergebnis zurück, während ein Callable
-Objekt ein Ergebnis zurückgibt.Runnable
-Objekt kann keine geprüfte Ausnahme auslösen, während ein Callable
-Objekt eine __.-Ausnahme auslösen kann.Runnable
-Schnittstelle gibt es seit Java 1.0, wohingegen Callable
nur in Java 1.5 eingeführt wurde.Nur wenige Ähnlichkeiten beinhalten
Methoden in der ExecutorService-Schnittstelle sind
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Zweck dieser Schnittstellen aus der Oracle-Dokumentation:
Runable interface sollte von jeder Klasse implementiert werden, deren Instanzen von einer Thread
ausgeführt werden sollen. Die Klasse muss eine Methode ohne Argumente mit dem Namen run
definieren.
Callable : Eine Aufgabe, die ein Ergebnis zurückgibt und möglicherweise eine Ausnahme auslöst. Implementierer definieren eine einzige Methode ohne Argumente, die als Aufruf ..__ bezeichnet wird. Die Callable
-Schnittstelle ähnelt Runnable
, da beide für Klassen konzipiert sind, deren Instanzen möglicherweise von einem anderen Thread ausgeführt werden. Eine Runnable
gibt jedoch kein Ergebnis zurück und kann keine geprüfte Ausnahme auslösen.
Andere Unterschiede:
Sie können Runnable
übergeben, um einen Thread zu erstellen. Sie können jedoch keinen neuen Thread erstellen, indem Sie Callable
als Parameter übergeben. Sie können Callable nur an ExecutorService
-Instanzen übergeben.
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();
}
}
Verwenden Sie Runnable
für Feuer und vergessen Sie Anrufe. Verwenden Sie Callable
, um das Ergebnis zu überprüfen.
Anders als Callable
kann Runnable
an die invokeAll -Methode übergeben werden. Die Methoden invokeAny
und invokeAll
führen die gebräuchlichsten Formen der Massenausführung aus, führen eine Auflistung von Aufgaben aus und warten, bis mindestens eine oder alle Aufgaben abgeschlossen sind
Trivialer Unterschied: Methodenname, der implementiert werden soll => run()
für Runnable
und call()
für Callable
.
Wie bereits erwähnt wurde, ist Callable eine relativ neue Schnittstelle und wurde als Teil des Parallelitätspakets eingeführt. Sowohl Callable als auch Runnable können mit Executoren verwendet werden. Klassen-Thread (der Runnable selbst implementiert) unterstützt nur Runnable.
Sie können Runnable weiterhin mit Executoren verwenden. Der Vorteil von Callable ist, dass Sie es an den Executor senden können und sofort ein zukünftiges Ergebnis erhalten, das nach Abschluss der Ausführung aktualisiert wird. Dasselbe kann mit Runnable implementiert werden, aber in diesem Fall müssen Sie die Ergebnisse selbst verwalten. Sie können beispielsweise eine Ergebniswarteschlange erstellen, die alle Ergebnisse enthält. Andere Threads können in dieser Warteschlange warten und sich mit den eingehenden Ergebnissen befassen.
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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 |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
Die Entwickler von Java hatten das Bedürfnis, die Fähigkeiten der Runnable
-Schnittstelle zu erweitern, wollten jedoch die Verwendung der Runnable
-Schnittstelle nicht beeinträchtigen. Dies war wahrscheinlich der Grund, warum sie in Java 1.5 eine separate Schnittstelle namens Callable
hatten Ändern der bereits vorhandenen Runnable
-Schnittstelle, die seit Java 1.0 Bestandteil von Java ist. Quelle
Der Unterschied zwischen Callable und Runable ist folgender:
Callable und Runnable Beide sind einander ähnlich und können zur Implementierung von Thread verwendet werden. Im Falle der Implementierung von Runnable müssen Sie run () method implementieren, aber im Fall von callable müssen Sie call () method implementieren. Beide Methoden funktionieren auf ähnliche Weise, jedoch als callable call () Methode haben mehr Flexibilität. Es gibt einige Unterschiede zwischen ihnen.
Unterschied zwischen lauffähig und anrufbar wie unten--
1) Die run () Methode von runnable Returns void bedeutet, wenn Sie möchten, dass Ihr Thread etwas zurückgibt, das Sie weiter verwenden können, dann haben Sie keine Wahl mit Runnable run () Methode. Es gibt eine Lösung 'Callable' , Wenn Sie etwas in Form von object zurückgeben möchten, sollten Sie Callable anstelle von Runnable verwenden. Aufrufbare Schnittstelle hat die Methode 'call ()', die Object zurückgibt.
Methodensignatur - Lauffähig->
public void run(){}
Callable->
public Object call(){}
2) Im Fall von Run run () method muss eine geprüfte Ausnahme auftreten. Sie müssen müssen mit try catch block behandelt werden, im Fall von Callable () method müssen Sie kann geprüfte Ausnahme werfen wie unten
public Object call() throws Exception {}
3) Runable kommt aus der älteren Java 1.0 Version, aber aufrufbar ist in Java 1.5 Version mit Executer Framework.
Wenn Sie mit Executers vertraut sind, sollten Sie Callable anstelle von Runnable verwenden.
Ich hoffe du verstehst.
Runnable (vs) Callable kommt zum Tragen, wenn wir das Executer-Framework verwenden.
ExecutorService ist eine Unterschnittstelle von Executor
, die sowohl ausführbare als auch aufrufbare Tasks akzeptiert.
Ein früheres Multithreading kann über das InterfaceRunnable
erreicht werden.Seit 1.0, aber hier ist das Problem, dass wir nach Abschluss der Thread-Aufgabe die Threads-Informationen nicht erfassen können. Zur Erfassung der Daten können statische Felder verwendet werden.
Beispiel Separate Threads zum Sammeln der Schülerdaten.
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() );
}
Um dieses Problem zu beheben, haben sieCallable<V>
eingeführt.Seit 1.5 Dies gibt ein Ergebnis zurück und kann eine Ausnahme auslösen.
Single Abstract Method : Sowohl Callable als auch Runnable Interface haben eine einzige abstrakte Methode, was bedeutet, dass sie in Lambda-Ausdrücken in Java 8 verwendet werden können.
public interface Runnable {
public void run();
}
public interface Callable<Object> {
public Object call() throws Exception;
}
Es gibt verschiedene Möglichkeiten, Aufgaben zur Ausführung an einen ExecutorService zu delegieren.
execute(Runnable task):void
erstellt einen neuen Thread, blockiert jedoch nicht den Haupt- oder Aufruferthread, da diese Methode void zurückgibt.submit(Callable<?>):Future<?>
, submit(Runnable):Future<?>
erstellt einen neuen Thread und blockiert den Haupt-Thread, wenn Sie future.get () verwenden.Beispiel für die Verwendung von Interfaces, die mit dem Executor-Framework ausführbar und aufrufbar sind.
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();
}
}