Der Unterschied zwischen den Schnittstellen Runnable und Callable in Java
492
Was ist der Unterschied zwischen der Verwendung der Runnableund der CallableSchnittstelle und beim Entwerfen eines gleichzeitigen Threads in Java. Warum sollten Sie einen über den anderen wählen?
Die Callable-Schnittstelle ähnelt Runnable, da beide für Klassen ausgelegt sind, deren Instanzen möglicherweise von einem anderen Thread ausgeführt werden. Ein Runnable gibt jedoch kein Ergebnis zurück und kann keine aktivierte Ausnahme auslösen.
Was ist die Notwendigkeit, beides zu haben, wenn Callablealles möglich Runnableist?
Weil die RunnableSchnittstelle nicht alles kann , was sie Callabletut!
Runnablegibt es seit Java 1.0, wurde aber Callablenur in Java 1.5 eingeführt ... um Anwendungsfälle zu behandeln, Runnabledie nicht unterstützt werden. 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 beeinträchtigt und eine Neukodierung erforderlich gemacht, wenn alter Java-Code auf neuere JVMs migriert wird. Das ist ein GROSSES 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 , wo eine Aufgabe nicht brauchen ein Ergebnis oder werfen eine geprüfte Ausnahme zurückzukehren. In diesen Anwendungsfällen ist die Verwendung Runnableprägnanter als die Verwendung Callable<Void>und Rückgabe eines Dummy ( null) - Werts aus der call()Methode.
Ich frage mich, woher du diese Geschichte hast. Das ist sehr nützlich.
Spiderman
4
@prash - die grundlegenden Fakten sind in alten Lehrbüchern zu finden. Wie die erste Ausgabe von Java auf den Punkt gebracht.
Stephen C
4
(@prash - Auch ... indem Sie anfangen, Java in der Java 1.1-Ära zu verwenden.)
Stephen C
1
@StephenC Wenn ich Ihre Antwort richtig gelesen habe, schlagen Sie vor, dass sie Runnable(weitgehend) aus Gründen der Abwärtskompatibilität existiert. Aber gibt es nicht Situationen, in denen die Implementierung (oder Anforderung) einer CallableSchnittstelle (z. B. in ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)) unnötig oder zu teuer ist ? Gibt es also keinen Vorteil, wenn beide Schnittstellen in der Sprache beibehalten werden, obwohl die Historie das aktuelle Ergebnis nicht erzwungen hat?
Max
1
@max - Nun, das habe ich gesagt, und dem stimme ich immer noch zu. Dies ist jedoch ein sekundärer Grund. Trotzdem vermute ich, dass Runnabledies geändert worden wäre, wenn es keine Notwendigkeit gegeben hätte, die Kompatibilität aufrechtzuerhalten. Das "Boilerplate" von return null;ist ein schwaches Argument. (Zumindest wäre das meine Entscheidung gewesen ... in dem hypothetischen Kontext, in dem man die Abwärtskompatibilität ignorieren könnte.)
Stephen C
82
Eine Methode Callablemuss implementiert call()werden, während eine Methode Runnableimplementiert run()werden muss.
A Callablekann einen Wert zurückgeben, a Runnablejedoch nicht.
A Callablekann eine geprüfte Ausnahme auslösen, A Runnablejedoch nicht.
A Callablekann mit ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)Methoden verwendet werden, a Runnablejedoch nicht.
publicinterfaceRunnable{void run();}publicinterfaceCallable<V>{
V call()throwsException;}
ExecutorService.submit (Runnable Task) existiert ebenfalls und ist sehr nützlich
Yair Kukielka
Runnable kann auch mit ExecutorService auf folgende Weise verwendet werden: 1) ExecutorService.execute (Runnable) 2) ExecutorService.submit (Runnable)
Azam Khan
2
Es gibt auch Executor.submit (Callable <T> -Aufgabe), aber Sie können nicht All oder InvokeAny mit einer Sammlung von ausführbaren Aufgaben aufrufen. Collection <? erweitert Callable <T>> Aufgaben
Nikli
36
Ich habe dies in einem anderen Blog gefunden, der diese Unterschiede etwas näher erläutern kann :
Obwohl beide Schnittstellen von den Klassen implementiert werden, die in einem anderen Ausführungsthread ausgeführt werden möchten, gibt es nur wenige Unterschiede zwischen den beiden Schnittstellen:
Eine Callable<V>Instanz gibt ein Ergebnis vom Typ zurück V, eine RunnableInstanz jedoch nicht.
Eine Callable<V>Instanz kann geprüfte Ausnahmen auslösen, eine RunnableInstanz jedoch nicht
Die Entwickler von Java hatten das Bedürfnis, die Funktionen der RunnableSchnittstelle zu erweitern, aber sie wollten die Verwendung der RunnableSchnittstelle nicht beeinflussen , und wahrscheinlich war dies der Grund, warum sie sich für eine separate Schnittstelle mit dem Namen CallableJava 1.5 entschieden haben, anstatt die bereits zu ändern vorhanden Runnable.
Schauen wir uns an, wo man Runnable und Callable verwenden würde.
Runnable und Callable werden beide auf einem anderen Thread als dem aufrufenden Thread ausgeführt. Callable kann jedoch einen Wert zurückgeben und Runnable nicht. Wo trifft das wirklich zu?
Runnable : Wenn Sie eine Feuer- und Vergessensaufgabe haben, verwenden Sie Runnable. Fügen Sie Ihren Code in eine ausführbare Datei ein, und 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 aus einer Aufgabe abzurufen, verwenden Sie Callable. Jetzt allein aufrufbar macht den Job nicht. Sie benötigen eine Zukunft, die Sie um Ihr Callable wickeln und Ihre Werte auf future.get () abrufen. Hier wird der aufrufende Thread blockiert, bis die Zukunft mit Ergebnissen zurückkommt, die wiederum auf die Ausführung der call () -Methode von Callable warten.
Stellen Sie sich also eine Schnittstelle zu einer Zielklasse vor, in der sowohl Runnable- als auch Callable-Wrapped-Methoden definiert sind. Die aufrufende Klasse ruft zufällig Ihre Schnittstellenmethoden auf, ohne zu wissen, welche ausführbar und welche aufrufbar ist. Die Runnable-Methoden werden asynchron ausgeführt, bis eine Callable-Methode aufgerufen wird. Hier wird der Thread der aufrufenden Klasse blockiert, da Sie Werte aus Ihrer Zielklasse abrufen.
ANMERKUNG: Innerhalb Ihrer Zielklasse können Sie Callable und Runnable auf einem einzelnen Thread-Executor aufrufen, 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 eingeschlossene Callable-Methode 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.
CallableDie Schnittstelle deklariert die call()Methode und Sie müssen Generika angeben, da der Typ des Objektaufrufs () Folgendes zurückgeben sollte:
publicinterfaceCallable<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()throwsException;}
RunnableAuf der anderen Seite befindet sich eine Schnittstelle, die eine run()Methode deklariert , die aufgerufen wird, wenn Sie einen Thread mit der ausführbaren Datei erstellen und start () aufrufen. Sie können run () auch direkt aufrufen, aber das, was nur die run () -Methode ausführt, ist der gleiche Thread.
publicinterfaceRunnable{/**
* 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()
*/publicabstractvoid run();}
Um einige bemerkenswerte Unterschiede zusammenzufassen sind
Ein RunnableObjekt gibt kein Ergebnis zurück, während ein CallableObjekt ein Ergebnis zurückgibt.
Ein RunnableObjekt kann keine aktivierte Ausnahme auslösen, während ein CallableObjekt eine Ausnahme auslösen kann.
Die RunnableSchnittstelle gibt es seit Java 1.0, während sie Callablenur in Java 1.5 eingeführt wurde.
Einige Ähnlichkeiten schließen ein
Instanzen der Klassen, die Runnable- oder Callable-Schnittstellen implementieren, werden möglicherweise von einem anderen Thread ausgeführt.
Die Instanz von Callable- und Runnable-Schnittstellen kann von ExecutorService über die Methode submit () ausgeführt werden.
Beide sind funktionale Schnittstellen und können seit Java8 in Lambda-Ausdrücken verwendet werden.
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:
Die ausführbare Schnittstelle sollte von jeder Klasse implementiert werden, deren Instanzen von a ausgeführt werden sollen Thread. Die Klasse muss eine Methode definieren, für die keine Argumente aufgerufen werden run.
Callable : Eine Aufgabe, die ein Ergebnis zurückgibt und möglicherweise eine Ausnahme auslöst . Implementierer definieren eine einzelne Methode ohne Argumente, die als Aufruf bezeichnet werden. Die CallableSchnittstelle ist insofern ähnlich Runnable, als beide für Klassen ausgelegt sind, deren Instanzen möglicherweise von einem anderen Thread ausgeführt werden. A Runnablegibt jedoch kein Ergebnis zurück und kann keine aktivierte Ausnahme auslösen.
Andere Unterschiede:
Sie können übergeben Runnable, um einen Thread zu erstellen . Sie können jedoch keinen neuen Thread erstellen, indem Sie ihn Callableals Parameter übergeben. Sie können Callable nur an ExecutorServiceInstanzen übergeben.
publicclassHelloRunnableimplementsRunnable{publicvoid run(){System.out.println("Hello from a thread!");}publicstaticvoid main(String args[]){(newThread(newHelloRunnable())).start();}}
Verwenden Sie Runnablefür Feuer und vergessen Sie Anrufe. Verwenden Sie Callablediese Option, um das Ergebnis zu überprüfen.
Callablekann anders als an die invokeAll- Methode übergeben werden Runnable. Methoden invokeAnyund invokeAllführen Sie die am häufigsten verwendeten Formen der Massenausführung aus, führen Sie eine Sammlung von Aufgaben aus und warten Sie, bis mindestens eine oder alle abgeschlossen sind
Trivialer Unterschied: zu implementierender Methodenname => run()für Runnableund call()für Callable.
Wie hier bereits erwähnt, 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. Class 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 und sofort das zukünftige Ergebnis zurückerhalten können, das aktualisiert wird, wenn die Ausführung abgeschlossen ist. Das gleiche kann mit Runnable implementiert werden, aber in diesem Fall müssen Sie die Ergebnisse selbst verwalten. Beispielsweise können Sie eine Ergebniswarteschlange erstellen, die alle Ergebnisse enthält. Andere Threads können in dieser Warteschlange warten und die eingehenden Ergebnisse verarbeiten.
Ich frage mich, was ist das Beispiel für einen Thread, der eine Ausnahme in Java auslöst. Wird der Haupt-Thread diese Ausnahme abfangen können? Wenn nicht, würde ich Callable nicht verwenden. Alex, hast du einen Einblick dazu? Vielen Dank!
Billionen
1
Code, der wie jeder andere Code in einem benutzerdefinierten Thread ausgeführt wird, kann eine Ausnahme auslösen. Um es in einem anderen Thread zu fangen, müssen Sie einige Anstrengungen unternehmen, indem Sie entweder einen benutzerdefinierten Benachrichtigungsmechanismus (z. B. basierend auf Listenern) verwenden Futureoder einen Hook verwenden oder hinzufügen, der alle nicht erworbenen Ausnahmen abfängt: docs.oracle.com/javase/6/docs/api/ java / lang /…
AlexR
Tolle Infos! Danke, Alex! :)
Billionen
1
Ich habe diese Antwort positiv bewertet, weil sie bestätigt (korrekt, wenn sie zum Nennwert angenommen wird), dass das Thread-Pool-Modell mit aufrufbaren Objekten verwendet werden muss. Das anscheinend Unglückliche daran ist, dass man Threaddie CallableBenutzeroberfläche nicht sinnvoll nutzen kann, damit ein einzelner Thread angepasst werden kann, um aufrufbare Dinge und andere Dinge zu tun, die der Entwickler möglicherweise möchte. Wenn jemand, der diesen Kommentar liest, meint, ich
8
+-------------------------------------+--------------------------------------------------------------------------------------------------+|Runnable|Callable<T>|+-------------------------------------+--------------------------------------------------------------------------------------------------+|Introduced in Java1.0 of java.lang |Introduced in Java1.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 throwCheckedExceptions|CanthrowCheckedExceptions|+-------------------------------------+--------------------------------------------------------------------------------------------------+
Die Entwickler von Java hatten das Bedürfnis, die Funktionen der RunnableSchnittstelle zu erweitern, aber sie wollten die Verwendung der RunnableSchnittstelle nicht beeinflussen , und wahrscheinlich war dies der Grund, warum sie sich für eine separate Schnittstelle mit dem Namen CallableJava 1.5 entschieden haben, anstatt die bereits zu ändern vorhandene RunnableSchnittstelle, die seit Java 1.0 Teil von Java ist. Quelle
Der Unterschied zwischen Callable und Runnable ist folgender:
Callable wird in JDK 5.0 eingeführt, Runnable wird in JDK 1.0 eingeführt
Callable hat die Methode call (), aber Runnable hat die Methode run ().
Callable hat eine Aufrufmethode, die einen Wert zurückgibt, aber Runnable hat eine Ausführungsmethode, die keinen Wert zurückgibt.
Die Aufrufmethode kann eine geprüfte Ausnahme auslösen, die Ausführungsmethode kann jedoch keine geprüfte Ausnahme auslösen.
Callable verwendet die Methode submit (), um sie in die Taskwarteschlange zu stellen, aber Runnable verwendet die Methode execute (), um sie in die Taskwarteschlange zu stellen.
Es ist wichtig zu betonen, dass diese Ausnahme aktiviert ist, nicht die RuntimeException
BertKing
5
Callable und Runnable sind einander ähnlich und können bei der Implementierung von Threads verwendet werden. Bei der Implementierung von Runnable müssen Sie die run () -Methode implementieren. Bei callable müssen Sie die call () -Methode implementieren. Beide Methoden funktionieren auf ähnliche Weise, aber die callable call () -Methode bietet mehr Flexibilität. Es gibt einige Unterschiede zwischen ihnen.
Der Unterschied zwischen Runnable und aufrufbar als below--
1) Die run () -Methode von runnable gibt void zurück . Wenn Sie möchten, dass Ihr Thread etwas zurückgibt , das Sie weiter verwenden können, haben Sie mit der runnable run () -Methode keine Wahl . Es gibt eine Lösung 'Callable' . Wenn Sie etwas in Form eines Objekts zurückgeben möchten, sollten Sie Callable anstelle von Runnable verwenden . Die aufrufbare Schnittstelle hat die Methode 'call ()', die Object zurückgibt .
Methodensignatur - Runnable->
publicvoid run(){}
Callable->
publicObject call(){}
2) Wenn bei der Runnable run () -Methode eine aktivierte Ausnahme auftritt, müssen Sie mit dem try catch-Block umgehen. Bei der Callable call () -Methode können Sie die aktivierte Ausnahme wie folgt auslösen
publicObject call()throwsException{}
3) Runnable kommt von Legacy - Java - 1.0 - Version, aber aufrufbar kam in Java 1.5 Version mit Executer Rahmen.
Wenn Sie sind vertraut mit Vollstrecker , dann sollten Sie aufrufbare anstelle von Runnable .
Runnable (vs) Callable kommt zum Tragen , wenn wir das Executer-Framework verwenden.
ExecutorService ist eine Subschnittstelle von Executor, die sowohl ausführbare als auch aufrufbare Aufgaben akzeptiert.
Ein früheres Multithreading kann über die Schnittstelle seit 1.0 erreicht werden. Hier besteht das Problem jedoch darin, dass nach Abschluss der Thread-Aufgabe die Thread-Informationen nicht erfasst werden können. Um die Daten zu sammeln, können wir statische Felder verwenden.Runnable
Beispiel Separate Threads zum Sammeln der Schülerdaten.
staticHashMap<String,List> multiTasksData =newHashMap();publicstaticvoid main(String[] args){Thread t1 =newThread(newRunnableImpl(1),"T1");Thread t2 =newThread(newRunnableImpl(2),"T2");Thread t3 =newThread(newRunnableImpl(3),"T3");
multiTasksData.put("T1",newArrayList());// later get the value and update it.
multiTasksData.put("T2",newArrayList());
multiTasksData.put("T3",newArrayList());}
Um dieses Problem zu beheben, haben sie Since 1.5 eingeführt, das ein Ergebnis zurückgibt und möglicherweise eine Ausnahme auslöst.Callable<V>
Einzelne abstrakte Methode : Sowohl die Callable- als auch die Runnable-Schnittstelle verfügen über eine einzige abstrakte Methode. Dies bedeutet, dass sie in Lambda-Ausdrücken in Java 8 verwendet werden können.
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-Thread oder den Aufrufer-Thread, da diese Methode void zurückgibt.
submit(Callable<?>):Future<?>, erstellt einen submit(Runnable):Future<?>neuen Thread und blockiert den Hauptthread, wenn Sie future.get () verwenden .
Beispiel für die Verwendung von Interfaces Runnable, Callable with Executor Framework.
classCallableTaskimplementsCallable<Integer>{privateint num =0;publicCallableTask(int num){this.num = num;}@OverridepublicInteger call()throwsException{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;}}classRunnableTaskimplementsRunnable{privateint num =0;publicRunnableTask(int num){this.num = num;}@Overridepublicvoid 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);}}publicclassMainThread_Wait_TillWorkerThreadsComplete{publicstaticvoid main(String[] args)throwsInterruptedException,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...");}publicstaticvoid runnableThreads()throwsInterruptedException,ExecutionException{ExecutorService executor =Executors.newFixedThreadPool(4);Future<?> f1 = executor.submit(newRunnableTask(5));Future<?> f2 = executor.submit(newRunnableTask(2));Future<?> f3 = executor.submit(newRunnableTask(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();}publicstaticvoid callableThreads()throwsInterruptedException,ExecutionException{ExecutorService executor =Executors.newFixedThreadPool(4);Future<Integer> f1 = executor.submit(newCallableTask(5));Future<Integer> f2 = executor.submit(newCallableTask(2));Future<Integer> f3 = executor.submit(newCallableTask(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();}}
Antworten:
Siehe Erklärung hier .
quelle
Grundsätzlich ja. Siehe die Antworten auf diese Frage . Und der Javadoc für
Callable
.Weil die
Runnable
Schnittstelle nicht alles kann , was sieCallable
tut!Runnable
gibt es seit Java 1.0, wurde aberCallable
nur in Java 1.5 eingeführt ... um Anwendungsfälle zu behandeln,Runnable
die nicht unterstützt werden. Theoretisch hätte das Java-Team die Signatur derRunnable.run()
Methode ändern können, dies hätte jedoch die Binärkompatibilität mit Code vor 1.5 beeinträchtigt und eine Neukodierung erforderlich gemacht, wenn alter Java-Code auf neuere JVMs migriert wird. Das ist ein GROSSES 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 , wo eine Aufgabe nicht brauchen ein Ergebnis oder werfen eine geprüfte Ausnahme zurückzukehren. In diesen Anwendungsfällen ist die Verwendung
Runnable
prägnanter als die VerwendungCallable<Void>
und Rückgabe eines Dummy (null
) - Werts aus dercall()
Methode.quelle
Runnable
(weitgehend) aus Gründen der Abwärtskompatibilität existiert. Aber gibt es nicht Situationen, in denen die Implementierung (oder Anforderung) einerCallable
Schnittstelle (z. B. inScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
) unnötig oder zu teuer ist ? Gibt es also keinen Vorteil, wenn beide Schnittstellen in der Sprache beibehalten werden, obwohl die Historie das aktuelle Ergebnis nicht erzwungen hat?Runnable
dies geändert worden wäre, wenn es keine Notwendigkeit gegeben hätte, die Kompatibilität aufrechtzuerhalten. Das "Boilerplate" vonreturn null;
ist ein schwaches Argument. (Zumindest wäre das meine Entscheidung gewesen ... in dem hypothetischen Kontext, in dem man die Abwärtskompatibilität ignorieren könnte.)Callable
muss implementiertcall()
werden, während eine MethodeRunnable
implementiertrun()
werden muss.Callable
kann einen Wert zurückgeben, aRunnable
jedoch nicht.Callable
kann eine geprüfte Ausnahme auslösen, ARunnable
jedoch nicht.A
Callable
kann mitExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
Methoden verwendet werden, aRunnable
jedoch nicht.quelle
Ich habe dies in einem anderen Blog gefunden, der diese Unterschiede etwas näher erläutern kann :
Obwohl beide Schnittstellen von den Klassen implementiert werden, die in einem anderen Ausführungsthread ausgeführt werden möchten, gibt es nur wenige Unterschiede zwischen den beiden Schnittstellen:
Callable<V>
Instanz gibt ein Ergebnis vom Typ zurückV
, eineRunnable
Instanz jedoch nicht.Callable<V>
Instanz kann geprüfte Ausnahmen auslösen, eineRunnable
Instanz jedoch nichtDie Entwickler von Java hatten das Bedürfnis, die Funktionen der
Runnable
Schnittstelle zu erweitern, aber sie wollten die Verwendung derRunnable
Schnittstelle nicht beeinflussen , und wahrscheinlich war dies der Grund, warum sie sich für eine separate Schnittstelle mit dem NamenCallable
Java 1.5 entschieden haben, anstatt die bereits zu ändern vorhandenRunnable
.quelle
Schauen wir uns an, wo man Runnable und Callable verwenden würde.
Runnable und Callable werden beide auf einem anderen Thread als dem aufrufenden Thread ausgeführt. Callable kann jedoch einen Wert zurückgeben und Runnable nicht. Wo trifft das wirklich zu?
Runnable : Wenn Sie eine Feuer- und Vergessensaufgabe haben, verwenden Sie Runnable. Fügen Sie Ihren Code in eine ausführbare Datei ein, und 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 aus einer Aufgabe abzurufen, verwenden Sie Callable. Jetzt allein aufrufbar macht den Job nicht. Sie benötigen eine Zukunft, die Sie um Ihr Callable wickeln und Ihre Werte auf future.get () abrufen. Hier wird der aufrufende Thread blockiert, bis die Zukunft mit Ergebnissen zurückkommt, die wiederum auf die Ausführung der call () -Methode von Callable warten.
Stellen Sie sich also eine Schnittstelle zu einer Zielklasse vor, in der sowohl Runnable- als auch Callable-Wrapped-Methoden definiert sind. Die aufrufende Klasse ruft zufällig Ihre Schnittstellenmethoden auf, ohne zu wissen, welche ausführbar und welche aufrufbar ist. Die Runnable-Methoden werden asynchron ausgeführt, bis eine Callable-Methode aufgerufen wird. Hier wird der Thread der aufrufenden Klasse blockiert, da Sie Werte aus Ihrer Zielklasse abrufen.
ANMERKUNG: Innerhalb Ihrer Zielklasse können Sie Callable und Runnable auf einem einzelnen Thread-Executor aufrufen, 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 eingeschlossene Callable-Methode 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.
quelle
Callable
Die Schnittstelle deklariert diecall()
Methode und Sie müssen Generika angeben, da der Typ des Objektaufrufs () Folgendes zurückgeben sollte:Runnable
Auf der anderen Seite befindet sich eine Schnittstelle, die einerun()
Methode deklariert , die aufgerufen wird, wenn Sie einen Thread mit der ausführbaren Datei erstellen und start () aufrufen. Sie können run () auch direkt aufrufen, aber das, was nur die run () -Methode ausführt, ist der gleiche Thread.Um einige bemerkenswerte Unterschiede zusammenzufassen sind
Runnable
Objekt gibt kein Ergebnis zurück, während einCallable
Objekt ein Ergebnis zurückgibt.Runnable
Objekt kann keine aktivierte Ausnahme auslösen, während einCallable
Objekt eine Ausnahme auslösen kann.Runnable
Schnittstelle gibt es seit Java 1.0, während sieCallable
nur in Java 1.5 eingeführt wurde.Einige Ähnlichkeiten schließen ein
Methoden in der ExecutorService-Schnittstelle sind
quelle
Zweck dieser Schnittstellen aus der Oracle-Dokumentation:
Die ausführbare Schnittstelle sollte von jeder Klasse implementiert werden, deren Instanzen von a ausgeführt werden sollen
Thread
. Die Klasse muss eine Methode definieren, für die keine Argumente aufgerufen werdenrun
.Callable : Eine Aufgabe, die ein Ergebnis zurückgibt und möglicherweise eine Ausnahme auslöst . Implementierer definieren eine einzelne Methode ohne Argumente, die als Aufruf bezeichnet werden. Die
Callable
Schnittstelle ist insofern ähnlichRunnable
, als beide für Klassen ausgelegt sind, deren Instanzen möglicherweise von einem anderen Thread ausgeführt werden. ARunnable
gibt jedoch kein Ergebnis zurück und kann keine aktivierte Ausnahme auslösen.Andere Unterschiede:
Sie können übergeben
Runnable
, um einen Thread zu erstellen . Sie können jedoch keinen neuen Thread erstellen, indem Sie ihnCallable
als Parameter übergeben. Sie können Callable nur anExecutorService
Instanzen übergeben.Beispiel:
Verwenden Sie
Runnable
für Feuer und vergessen Sie Anrufe. Verwenden SieCallable
diese Option, um das Ergebnis zu überprüfen.Callable
kann anders als an die invokeAll- Methode übergeben werdenRunnable
. MethodeninvokeAny
undinvokeAll
führen Sie die am häufigsten verwendeten Formen der Massenausführung aus, führen Sie eine Sammlung von Aufgaben aus und warten Sie, bis mindestens eine oder alle abgeschlossen sindTrivialer Unterschied: zu implementierender Methodenname =>
run()
fürRunnable
undcall()
fürCallable
.quelle
Wie hier bereits erwähnt, 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. Class 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 und sofort das zukünftige Ergebnis zurückerhalten können, das aktualisiert wird, wenn die Ausführung abgeschlossen ist. Das gleiche kann mit Runnable implementiert werden, aber in diesem Fall müssen Sie die Ergebnisse selbst verwalten. Beispielsweise können Sie eine Ergebniswarteschlange erstellen, die alle Ergebnisse enthält. Andere Threads können in dieser Warteschlange warten und die eingehenden Ergebnisse verarbeiten.
quelle
Future
oder einen Hook verwenden oder hinzufügen, der alle nicht erworbenen Ausnahmen abfängt: docs.oracle.com/javase/6/docs/api/ java / lang /…Thread
dieCallable
Benutzeroberfläche nicht sinnvoll nutzen kann, damit ein einzelner Thread angepasst werden kann, um aufrufbare Dinge und andere Dinge zu tun, die der Entwickler möglicherweise möchte. Wenn jemand, der diesen Kommentar liest, meint, ichDie Entwickler von Java hatten das Bedürfnis, die Funktionen der
Runnable
Schnittstelle zu erweitern, aber sie wollten die Verwendung derRunnable
Schnittstelle nicht beeinflussen , und wahrscheinlich war dies der Grund, warum sie sich für eine separate Schnittstelle mit dem NamenCallable
Java 1.5 entschieden haben, anstatt die bereits zu ändern vorhandeneRunnable
Schnittstelle, die seit Java 1.0 Teil von Java ist. Quellequelle
Der Unterschied zwischen Callable und Runnable ist folgender:
quelle
Callable und Runnable sind einander ähnlich und können bei der Implementierung von Threads verwendet werden. Bei der Implementierung von Runnable müssen Sie die run () -Methode implementieren. Bei callable müssen Sie die call () -Methode implementieren. Beide Methoden funktionieren auf ähnliche Weise, aber die callable call () -Methode bietet mehr Flexibilität. Es gibt einige Unterschiede zwischen ihnen.
Der Unterschied zwischen Runnable und aufrufbar als below--
1) Die run () -Methode von runnable gibt void zurück . Wenn Sie möchten, dass Ihr Thread etwas zurückgibt , das Sie weiter verwenden können, haben Sie mit der runnable run () -Methode keine Wahl . Es gibt eine Lösung 'Callable' . Wenn Sie etwas in Form eines Objekts zurückgeben möchten, sollten Sie Callable anstelle von Runnable verwenden . Die aufrufbare Schnittstelle hat die Methode 'call ()', die Object zurückgibt .
Methodensignatur - Runnable->
Callable->
2) Wenn bei der Runnable run () -Methode eine aktivierte Ausnahme auftritt, müssen Sie mit dem try catch-Block umgehen. Bei der Callable call () -Methode können Sie die aktivierte Ausnahme wie folgt auslösen
3) Runnable kommt von Legacy - Java - 1.0 - Version, aber aufrufbar kam in Java 1.5 Version mit Executer Rahmen.
Wenn Sie sind vertraut mit Vollstrecker , dann sollten Sie aufrufbare anstelle von Runnable .
Ich hoffe du verstehst.
quelle
Runnable (vs) Callable kommt zum Tragen , wenn wir das Executer-Framework verwenden.
ExecutorService ist eine Subschnittstelle von
Executor
, die sowohl ausführbare als auch aufrufbare Aufgaben akzeptiert.Ein früheres Multithreading kann über die Schnittstelle seit 1.0 erreicht werden. Hier besteht das Problem jedoch darin, dass nach Abschluss der Thread-Aufgabe die Thread-Informationen nicht erfasst werden können. Um die Daten zu sammeln, können wir statische Felder verwenden.
Runnable
Beispiel Separate Threads zum Sammeln der Schülerdaten.
Um dieses Problem zu beheben, haben sie Since 1.5 eingeführt, das ein Ergebnis zurückgibt und möglicherweise eine Ausnahme auslöst.
Callable<V>
Einzelne abstrakte Methode : Sowohl die Callable- als auch die Runnable-Schnittstelle verfügen über eine einzige abstrakte Methode. Dies bedeutet, dass sie in Lambda-Ausdrücken in Java 8 verwendet werden können.
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-Thread oder den Aufrufer-Thread, da diese Methode void zurückgibt.submit(Callable<?>):Future<?>
, erstellt einensubmit(Runnable):Future<?>
neuen Thread und blockiert den Hauptthread, wenn Sie future.get () verwenden .Beispiel für die Verwendung von Interfaces Runnable, Callable with Executor Framework.
quelle
Es ist eine Art Namenskonvention für Schnittstellen, die mit der funktionalen Programmierung übereinstimmt
quelle