2016-05-26 21 views
6

Sono abbastanza nuovo in Java, stavo passando per i concetti di Multithreading, passando attraverso varie implementazioni di utilizzo del multithreading, ho esaminato questi due concetti. Questa domanda The difference between the Runnable and Callable interfaces in Java specifica qual è la differenza tra i due e dove usare.Dove usare callable e dove usare Runnable Interface?

Il mio dubbio è se Callable è in grado di eseguire tutto ciò che è eseguibile, perché così tante persone usano Runnable invece di callable? Ci sono delle spese generali extra nell'implementazione dell'interfaccia Callable rispetto a Inteface eseguibile?

+1

Non si dovrebbe usare Callable, se non è necessario. Come afferma [principio KISS] (https://people.apache.org/~fhanik/kiss.html). –

risposta

6

Prima che ci fosse il pacchetto java.util.concurrent, che è atterrato nella versione Java 5, non c'erano altre opzioni per eseguire calcoli simultanei, ma per manipolare direttamente i valori di Thread s.

È possibile manipolare direttamente i fili, ad es. sottoclasse:

public class MyThread extends Thread { 
    public void run() { 
     myComputation(); 
    } 
} 

Oppure si potrebbe fare lo stesso con la creazione di un Runnable, che era il modo preferito (soprattutto perché non è necessario creare una sottoclasse nulla, che prevede una netta separazione di preoccupazione, codice migliore riutilizzo o in generale , una composizione migliore):

public class MyRunnable implements Runnable { 
    public void run() { 
     mycomputation(); 
    } 
} 
new Thread(new MyRunnable()).start(); 

Ma non importa in che modo si è utilizzato, era necessario creare, lancio, manipolare, unirsi sui filetti. Che ha degli svantaggi: quanti thread puoi creare? È costoso questo? (Ad un certo punto lo è, anche se è diventato più economico ed economico con ogni implementazione JVM.)

Inoltre, questa API stessa presenta limitazioni che lo sviluppatore ha dovuto superare: cosa succede se voglio restituire un valore da un Runnable, vedere la firma non lo consente comunque? Come posso sapere se il mio Runnable non è riuscito con un Exception? Ci sono cose come i gestori di eccezioni e simili per consentire ciò con i thread, ma era un compito ripetitivo, incline agli errori.

Inserisce il pacchetto java.util.concurrent! Offre una risposta a tutto questo (e altro)!

Si desidera riutilizzare i thread per più di una "unità di lavoro" (sia esso un Runnable o no?): È possibile. Vuoi sapere se l'unità di lavoro è stata completata o fallita: puoi farlo. Vuoi restituire un valore: puoi. Vuoi dare priorità dinamiche ad alcuni compiti rispetto ad altri? Sicuro. Hai bisogno della possibilità di pianificare le attività? Può fare. E così via.

sostituire il vostro Runnable s con Callable s (questo è semplice come può essere, entrambi sono interfacce singolo metodo!), Smettere di manipolare Thread s in favore di Future s e lasciare l'impianto idraulico a ExecutorService.

Il mio dubbio è se Callable è in grado di fare tutto ciò che è eseguibile, perché così tante persone usano Runnable invece di callable?

Forse hanno un vecchio codice (Java 1.4?). Forse non sono a conoscenza dei vantaggi delle astrazioni di livello superiore e preferiscono le cose di livello basso Thread?

In generale, non vi è assolutamente alcun motivo per preferire l'utilizzo di Thread s dall'API simultanea.

Ci sono spese generali aggiuntive nell'implementazione dell'interfaccia Callable rispetto a Runnable Interface?

In "attuazione Callable" vs Runnable, non c'è nessuno. Ma c'è un costo per il nuovo materiale Callable perché internamente, tutto torna a Thread se Runnable s (almeno, le attuali implementazioni lo fanno). Ma potresti effettivamente ottenere prestazioni, grazie a nuove funzionalità come il più facile riutilizzo dei thread!

Quindi, sì, l'API simultanea ha il suo costo, ma è assolutamente, completamente trascurabile in qualsiasi caso d'uso standard, ma ha anche nuovi punti di forza che lo rendono migliore in molti modi, comprese le prestazioni.

Inoltre, si ottengono enormi nuove possibilità dall'API, come già affermato (consultare il framework Fork/Join, vedere i flussi paralleli in Java 8, ...) e ridurre la necessità di qualsiasi nodo di "personalizzato" , codice di concorrenza "autoprodotto" per dette funzionalità, che è notoriamente difficile da ottenere.

Il rapporto costi/benefici favorisce completamente la "nuova" API concorrente.

0

perché così tante persone usano Runnable invece di callable?

Callable è competitivo in jdk, che è dotato di framework Executor, offre maggiore flessibilità nell'esecuzione dei thread.

Ci sono delle spese generali supplementari in attuazione interfaccia richiamabile in confronto con Runnable Inteface?

Non penso, è molto semplice se si segue una documentazione standard di Executor.

2

Una differenza importante: il metodo run() nell'interfaccia Runnable restituisce void; il metodo call() nell'interfaccia Callable restituisce un oggetto di tipo T. Ciò consente di accedere facilmente a un oggetto risposta.

È possibile fare la stessa cosa con un'implementazione concreta di Runnable creando un membro dati privato e fornendo un getter, ma lo zucchero sintattico è dolce.

4

Il mio dubbio è se Callable è in grado di eseguire tutto ciò che è eseguibile, perché così tante persone usano Runnable invece di callable? Ci sono dei costi aggiuntivi aggiuntivi nell'implementazione dell'interfaccia Callable rispetto a Inteface eseguibile?

  1. Usa interfaccia Runnable per fuoco e dimenticare chiamate, soprattutto quando non si è interessati a seguito della esecuzione dell'attività.
  2. Non ci sono spese generali aggiuntive nell'implementazione dell'interfaccia Callable.

La differenza fondamentale dalla documentazione page

L'interfaccia Callable è simile a Runnable, in quanto entrambi sono progettati per classi le cui istanze sono potenzialmente eseguita da un altro thread. Un Runnable, tuttavia, non restituisce un risultato e non può generare un'eccezione controllata.

Consente controllare il codice sorgente di AbstractExecutorService

public Future<?> submit(Runnable task) { 
    if (task == null) throw new NullPointerException(); 
    RunnableFuture<Object> ftask = newTaskFor(task, null); 
    execute(ftask); 
    return ftask; 
} 


public <T> Future<T> submit(Callable<T> task) { 
    if (task == null) throw new NullPointerException(); 
    RunnableFuture<T> ftask = newTaskFor(task); 
    execute(ftask); 
    return ftask; 
} 

non vedo alcun overhead in esecuzione di Callable compito Callable utilizza internamente RunnableFuture<T>

0

mio dubbio è se richiamabile è capace di fare tutto ciò che è Runnable, perché così tante persone usano Runnable invece di callable?

Questa domanda equivale a chiedere: "Perché Java ha tipi statici?" Un'interfaccia è una dichiarazione di una firma del tipo in fase di compilazione, niente di più, niente di meno; e l'unica differenza tra due interfacce è rappresentata dai tipi in fase di compilazione degli argomenti e dai valori di ritorno.

Quindi perché Java ha tipi statici? Sfortunatamente, questa domanda è fuori dalla portata di StackOverflow. Puoi utilizzare Google per trovare tutto sulle lingue tipicamente statiche rispetto alle lingue digitate dinamicamente.

Inoltre, se vuoi dare un'occhiata ad un mondo diverso, puoi provare a scrivere del codice Ruby. Non ci sono interfacce in Ruby perché non ci sono tipi statici. I programmatori di Ruby parlano di "Duck Typing", che è un'altra buona frase per Google.

Problemi correlati