web-dev-qa-db-de.com

Der Unterschied zwischen den ausführbaren und den aufrufbaren Schnittstellen in Java

Was ist der Unterschied zwischen den Runnable- und Callable-Schnittstellen, wenn Sie einen gleichzeitigen Thread in Java entwerfen.

431
Scottm

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.

398
Jorge Ferreira

Was sind die Unterschiede in den Anwendungen von Runnable und Callable. Ist der Unterschied nur mit dem Rückgabeparameter in Callable 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, was Runnable 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().

253
Stephen C
  • Ein Callable muss die call()-Methode implementieren, während ein Runnable die run()-Methode implementieren muss.
  • Ein Callable kann einen Wert zurückgeben, ein Runnable jedoch nicht.
  • Eine 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;
    }
    
72
nikli

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:

  • Eine Callable<V>-Instanz gibt ein Ergebnis des Typs V zurück, eine Runnable-Instanz jedoch nicht.
  • Eine Callable<V>-Instanz kann geprüfte Ausnahmen auslösen, eine Runnable-Instanz jedoch nicht

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.

36
amoran

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.

26

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

  1. Ein Runnable-Objekt gibt kein Ergebnis zurück, während ein Callable-Objekt ein Ergebnis zurückgibt.
  2. Ein Runnable-Objekt kann keine geprüfte Ausnahme auslösen, während ein Callable-Objekt eine __.-Ausnahme auslösen kann.
  3. Die Runnable-Schnittstelle gibt es seit Java 1.0, wohingegen Callable nur in Java 1.5 eingeführt wurde.

Nur wenige Ähnlichkeiten beinhalten

  1. Instanzen der Klassen, die Runnable- oder Callable-Schnittstellen implementieren, werden möglicherweise Von einem anderen Thread ausgeführt.
  2. Die Instanzen von Callable- und Runnable-Schnittstellen können von ExecutorService über die submit () - Methode ausgeführt werden.
  3. 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);
14
Aniket Thakur

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:

  1. 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.

    Beispiel:

    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();
        }
    
    }
    
  2. Verwenden Sie Runnable für Feuer und vergessen Sie Anrufe. Verwenden Sie Callable, um das Ergebnis zu überprüfen.

  3. 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

  4. Trivialer Unterschied: Methodenname, der implementiert werden soll => run() für Runnable und call() für Callable.

14
Ravindra babu

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.

10
AlexR
+-------------------------------------+--------------------------------------------------------------------------------------------------+
|              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

5
Premraj

Der Unterschied zwischen Callable und Runable ist folgender:

  1. Callable wurde in JDK 5.0 eingeführt, Runnable jedoch in JDK 1.0
  2. Callable hat eine call () -Methode, aber Runnable hat eine run () -Methode.
  3. Callable hat eine Aufrufmethode, die einen Wert zurückgibt, aber Runnable hat eine Run-Methode, die keinen Wert zurückgibt.
  4. die Aufrufmethode kann eine geprüfte Ausnahme auslösen, die Ausführungsmethode kann jedoch keine geprüfte Ausnahme.
  5. Callable Verwenden Sie die submit () -Methode, um sie in die Task-Warteschlange einzufügen.
3
Raman Gupta

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.

0
Sudhakar Pandey

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 InterfaceRunnableerreicht 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();
    }
}
0
Yash