Het verschil tussen de Runnable en Callable interfaces in Java

Wat is het verschil tussen het gebruik van de Runnableen Callableinterfaces bij het ontwerpen van een gelijktijdige thread in Java, waarom zou je de ene boven de andere kiezen?


Antwoord 1, autoriteit 100%

Zie uitleg hier.

De oproepbare interface is vergelijkbaar met
Uit te voeren, in die zin dat beide zijn ontworpen
voor klassen waarvan de instanties zijn
mogelijk uitgevoerd door een ander
draad. Een Runnable echter niet
een resultaat retourneren en kan niet gooien
aangevinkte uitzondering.


Antwoord 2, autoriteit 62%

Wat zijn de verschillen in de toepassingen van Runnableen Callable. Is het verschil alleen met de return-parameter aanwezig in Callable?

In principe wel. Zie de antwoorden op deze vraag. En de javadoc voor Callable.

Wat is de noodzaak om beide te hebben als Callablealles kan wat Runnabledoet?

Omdat de Runnable-interface nietalles kan doen wat Callabledoet!

Runnablebestaat al sinds Java 1.0, maar Callablewerd pas geïntroduceerd in Java 1.5 … om use-cases af te handelen die Runnableondersteund niet. In theorie had het Java-team de handtekening van de Runnable.run()-methode kunnen wijzigen, maar dit zou de binaire compatibiliteit met pre-1.5-code hebben verbroken, waardoor hercodering nodig was bij het migreren van oude Java-code naar nieuwere JVM’s . Dat is een GROOT NEE-NEE. Java streeft ernaar achterwaarts compatibel te zijn … en dat is een van Java’s grootste verkoopargumenten voor zakelijk computergebruik.

En natuurlijk zijn er gevallen waarin een taak geeneen resultaat hoeft te retourneren of een gecontroleerde uitzondering hoeft te genereren. Voor die gevallen is het gebruik van Runnablebeknopter dan het gebruik van Callable<Void>en het retourneren van een dummy-waarde (null) van de call()methode.


Antwoord 3, autoriteit 19%

  • Een Callablemoet de call()-methode implementeren, terwijl een Runnablede run()-methode moet implementeren .
  • Een Callablekan een waarde retourneren, maar een Runnablekan dat niet.
  • Een Callablekan gecontroleerde uitzondering genereren, maar een Runnablekan dat niet.
  • Een Callablekan worden gebruikt met ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)-methoden maar een Runnablekan niet.

    public interface Runnable {
        void run();
    }
    public interface Callable<V> {
        V call() throws Exception;
    }
    

Antwoord 4, autoriteit 8%

Ik vond dit in een andere blog die het een beetje meer kan uitleggen deze verschillen:

Hoewel beide interfaces worden geïmplementeerd door de klassen die in een andere uitvoeringsthread willen worden uitgevoerd, zijn er weinig verschillen tussen de twee interfaces, namelijk:

  • Een Callable<V>-instantie retourneert een resultaat van het type V, terwijl een Runnable-instantie dat niet doet.
  • Een Callable<V>-instantie kan gecontroleerde uitzonderingen genereren, terwijl een Runnable-instantie dat niet kan

De ontwerpers van Java hadden behoefte aan uitbreiding van de mogelijkheden van de Runnable-interface, maar ze wilden het gebruik van de Runnable-interface niet beïnvloeden en waarschijnlijk dat was de reden waarom ze gingen voor een aparte interface genaamd Callablein Java 1.5 dan het wijzigen van de reeds bestaande Runnable.


Antwoord 5, autoriteit 7%

Laten we eens kijken waar we Runnable en Callable zouden gebruiken.

Uitvoerbaar en Oproepbaar werken beide op een andere thread dan de aanroepende thread. Maar Callable kan een waarde retourneren en Runnable niet. Dus waar is dit echt van toepassing.

Uitvoerbaar: als je een brand hebt en een taak vergeet, gebruik dan Uitvoerbaar. Plaats uw code in een Runnable en wanneer de methode run() wordt aangeroepen, kunt u uw taak uitvoeren. De bellende thread maakt het echt niet uit wanneer je je taak uitvoert.

Oproepbaar: als u een waarde uit een taak probeert op te halen, gebruik dan Oproepbaar. Nu alleen opvraagbaar zal het werk niet doen. Je hebt een Future nodig die je om je Callable wikkelt en je waarden krijgt op future.get (). Hier wordt de aanroepende thread geblokkeerd totdat de toekomst terugkomt met resultaten die op hun beurt wachten tot de call()-methode van Callable wordt uitgevoerd.

Dus denk aan een interface naar een doelklasse waar u zowel Runnable als Callable verpakte methoden hebt gedefinieerd. De aanroepende klasse roept willekeurig uw interface-methoden aan, niet wetende welke Runnable en welke Callable is. De Runnable-methoden worden asynchroon uitgevoerd totdat een Callable-methode wordt aangeroepen. Hier wordt de thread van de aanroepende klasse geblokkeerd omdat u waarden ophaalt van uw doelklasse.

OPMERKING: Binnen uw doelklasse kunt u de oproepen naar Callable en Runnable doen op een enkele thread-executor, waardoor dit mechanisme vergelijkbaar is met een wachtrij voor seriële verzending. Dus zolang de beller uw Runnable-verpakte methoden aanroept, wordt de aanroepende thread heel snel uitgevoerd zonder te blokkeren. Zodra het een Callable verpakt in Future-methode aanroept, moet het worden geblokkeerd totdat alle andere items in de wachtrij zijn uitgevoerd. Alleen dan keert de methode terug met waarden. Dit is een synchronisatiemechanisme.


Antwoord 6, autoriteit 4%

Callable-interface declareert call()-methode en u moet generieke gegevens opgeven als type Object call() zou moeten terugkeren –

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;
}

Runnableaan de andere kant is een interface die de methode run()declareert die wordt aangeroepen wanneer u een thread maakt met de uitvoerbare en oproep start() erop. Je kunt run() ook rechtstreeks aanroepen, maar dat voert alleen de methode run() uit in dezelfde thread.

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

Om een ​​paar opmerkelijke verschillen samen te vatten, zijn

  1. Een Runnable-object retourneert geen resultaat, terwijl een Callable-object een resultaat retourneert.
  2. Een Runnable-object kan geen aangevinkte uitzondering genereren, terwijl een Callable-object een
    uitzondering.
  3. De Runnable-interface bestaat al sinds Java 1.0, terwijl Callablepas werd geïntroduceerd
    in Java 1.5.

Er zijn maar weinig overeenkomsten

  1. Instances van de klassen die Runnable of Callable interfaces implementeren zijn mogelijk
    uitgevoerd door een andere thread.
  2. Instance van zowel aanroepbare als uitvoerbare interfaces kan worden uitgevoerd door ExecutorService via de methode submit().
  3. Beide zijn functionele interfaces en kunnen sinds Java8 in Lambda-expressies worden gebruikt.

Methoden in de ExecutorService-interface zijn

<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);

Antwoord 7, autoriteit 3%

Doel van deze interfaces uit Oracle-documentatie:

Uitvoerbare-interface moet worden geïmplementeerd door elke klasse waarvan de instanties bedoeld zijn om te worden uitgevoerd door een Thread. De klasse moet een methode definiëren zonder argumenten genaamd run.

Oproepbaar: een taak die een resultaat retourneert en een uitzondering kan veroorzaken. Implementors definiëren een enkele methode zonder argumenten die call worden genoemd.
De Callable-interface is vergelijkbaar met Runnable, in die zin dat beide zijn ontworpen voor klassen waarvan de instanties mogelijk door een andere thread worden uitgevoerd. Een Runnableretourneert echter geen resultaat en kan geen aangevinkte uitzondering genereren.

Andere verschillen:

  1. Je kunt Runnabledoorgeven om een ​​Thread. Maar u kunt geen nieuwe thread maken door Callableals parameter door te geven. U kunt Callable alleen doorgeven aan instanties van ExecutorService.

    Voorbeeld:

    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. Gebruik Runnablevoor vuur en vergeet oproepen. Gebruik Callableom het resultaat te verifiëren.

  3. Callablekan worden doorgegeven aan invokeAllmethode in tegenstelling tot Runnable. De methoden invokeAnyen invokeAllvoeren de meest bruikbare vormen van bulkuitvoering uit, waarbij een verzameling taken wordt uitgevoerd en vervolgens wordt gewacht tot ten minste één of alle taken zijn voltooid

  4. Triviaal verschil: naam van de methode die moet worden geïmplementeerd => run()voor Runnableen call()voor Callable.


Antwoord 8, autoriteit 3%

Zoals hier al vermeld, is Callable een relatief nieuwe interface en werd het geïntroduceerd als onderdeel van een gelijktijdigheidspakket. Zowel Callable als Runnable kunnen worden gebruikt met uitvoerders. Class Thread (die Runnable zelf implementeert) ondersteunt alleen Runnable.

U kunt Runnable nog steeds gebruiken met uitvoerders. Het voordeel van Callable dat u het naar de uitvoerder kunt sturen en onmiddellijk terugkrijgt Toekomstig resultaat dat zal worden bijgewerkt wanneer de uitvoering is voltooid. Hetzelfde kan worden geïmplementeerd met Runnable, maar in dit geval moet u de resultaten zelf beheren. U kunt bijvoorbeeld een resultatenwachtrij maken die alle resultaten bevat. Andere threads kunnen in deze wachtrij wachten en de resultaten afhandelen die binnenkomen.


Antwoord 9, autoriteit 2%

Het verschil tussen Callable en Runnable is als volgt:

  1. Callable is geïntroduceerd in JDK 5.0, maar Runnable is geïntroduceerd in JDK 1.0
  2. Callable heeft de methode call() maar Runnable heeft de methode run().
  3. Callable heeft een call-methode die waarde retourneert, maar Runnable heeft een run-methode die geen waarde retourneert.
  4. call-methode kan gecontroleerde uitzondering genereren, maar run-methode kan gecontroleerde uitzondering niet genereren.
  5. Aanroepbaar gebruik de methode submit() om in de taakwachtrij te plaatsen, maar uitvoerbaar gebruik de methode execute() om in de taakwachtrij te plaatsen.

Antwoord 10, autoriteit 2%

+----------------------------------------+--------------------------------------------------------------------------------------------------+
|              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 generic value V                                                        |
| No way to propagate checked exceptions | Callable's call()“throws Exception” clause so we can easily propagate checked exceptions further |                                                                     |
+----------------------------------------+--------------------------------------------------------------------------------------------------+

De ontwerpers van Java hadden behoefte aan uitbreiding van de mogelijkheden van de Runnable-interface, maar ze wilden het gebruik van de Runnable-interface niet beïnvloeden en waarschijnlijk dat was de reden waarom ze voor een aparte interface met de naam Callablein Java 1.5 gingen dan voor het wijzigen van de reeds bestaande Runnable-interface die sinds Java 1.0 deel uitmaakt van Java. bron


Antwoord 11, autoriteit 2%

Callable en Runnablebeide lijken op elkaar en kunnen worden gebruikt bij het implementeren van threads. Als u Uitvoerbaarimplementeert, moet u de methode run()implementeren, maar in het geval van aanroepbaar moet u de methode call()implementeren, beide methoden werkt op vergelijkbare manieren, maar de aanroepbare call()-methode heeft meer flexibiliteit. Er zijn enkele verschillen tussen beide.

Verschil tussen Uitvoerbaaren oproepbaarzoals hieronder–

1) De run()methode van runnableretourneert void, wat betekent dat als je wilt dat je thread iets retourneert dat je daarna kunt gebruiken je hebt geen keuze met de methode Runnable run(). Er is een oplossing ‘Callable’. Als je iets in de vorm van een objectwilt retourneren, moet je oproepbaar gebruiken in plaats van uitvoerbaar. Oproepbare interface heeft methode ‘call()’ die Object teruggeeft.

Methode handtekening –
uitvoerbaar->

public void run(){}

Oproepbaar->

public Object call(){}

2) In het geval van de Uitvoerbare run()-methode, als er een gecontroleerde uitzondering optreedt, moet u afhandelen met het try-catch-blok, maar in het geval van Oproepbare call()-methode die u kan gecontroleerde uitzondering genererenzoals hieronder

public Object call() throws Exception {}

3) Uitvoerbaarkomt uit de oude versie java 1.0, maar oproepbaarkwam in de Java 1.5-versie met Uitvoerderframework.

Als u bekend bent met Uitvoerders, moet u Oproepbaar gebruiken in plaats van Uitvoeren.

Ik hoop dat je het begrijpt.


Antwoord 12

Uitvoerbaar (vs) Oproepbaarkomt van pas wanneer we het Executer-framework gebruiken.

ExecutorService is een subinterface van Executor, die zowel uitvoerbare als oproepbare taken accepteert.

Vroegere Multi-Threading kan worden bereikt met behulp van Interface RunnableSinds 1.0, maar hier is het probleem na bij het voltooien van de threadtaak kunnen we de Threads-informatie niet verzamelen. Om de gegevens te verzamelen, kunnen we statische velden gebruiken.

Voorbeeld Aparte discussielijnen om gegevens van elke leerling te verzamelen.

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

Om dit probleem op te lossen hebben ze Callable<V>Sinds 1.5geïntroduceerd, wat een resultaat oplevert en gooi een uitzondering.

  • Enkele abstracte methode: zowel de oproepbare als de uitvoerbare interface hebben een enkele abstracte methode, wat betekent dat ze kunnen worden gebruikt in lambda-expressies in java 8.

    public interface Runnable {
    public void run();
    }
    public interface Callable<Object> {
        public Object call() throws Exception;
    }
    

Er zijn een paar verschillende manieren om taken voor uitvoering te delegeren aan een ExecutorService.

  • execute(Runnable task):voidplaatst een nieuwe thread maar blokkeert de hoofdthread of bellerthread niet omdat deze methode ongeldig retourneert.
  • submit(Callable<?>):Future<?>, submit(Runnable):Future<?>plaatst een nieuwe thread en blokkeert de hoofdthread wanneer je gebruikt future.get().

Voorbeeld van het gebruik van Interfaces Runnable, Callable met Executor-framework.

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

Antwoord 13

Het is een soort van een interface-naamgevingsconventie die overeenkomt met functionele programmering

//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 Exception;
}
...
//Executor
public interface Executor {
    void execute(Runnable command);
}

Antwoord 14

Naast alle andere antwoorden:

We kunnen niet vulbaar zijn voor een individuele draad voor uitvoering I.E. Callable kan alleen in het executorader worden gebruikt.
Maar het is flauwbaar, kan worden doorgegeven aan een individuele draad voor uitvoering (nieuwe draad (nieuwe customnable ())), evenals kan worden gebruikt in het executorader.

Other episodes