Risposte:
Vedi la spiegazione qui .
L'interfaccia Callable è simile a Runnable, in quanto entrambi sono progettati per classi le cui istanze sono potenzialmente eseguite da un altro thread. Un Runnable, tuttavia, non restituisce un risultato e non può generare un'eccezione controllata.
Quali sono le differenze nelle applicazioni di
Runnable
eCallable
. La differenza è presente solo con il parametro return inCallable
?
Fondamentalmente sì. Vedi le risposte a questa domanda . E il javadoc perCallable
.
Qual è la necessità di avere entrambi se
Callable
può fare tutto ciò cheRunnable
fa?
Perché l' Runnable
interfaccia non può fare tutto ciò che Callable
fa!
Runnable
esiste da Java 1.0, ma è Callable
stato introdotto solo in Java 1.5 ... per gestire casi d'uso che Runnable
non supportano. In teoria, il team Java avrebbe potuto modificare la firma del Runnable.run()
metodo, ma ciò avrebbe compromesso la compatibilità binaria con il codice pre-1.5, richiedendo la ricodifica durante la migrazione del vecchio codice Java alle nuove JVM. Questo è un GRANDE NO-NO. Java si sforza di essere retrocompatibile ... ed è stato uno dei maggiori punti di forza di Java per il business computing.
E, ovviamente, ci sono casi d'uso in cui un'attività non deve restituire un risultato o generare un'eccezione controllata. Per questi casi d'uso, l'utilizzo Runnable
è più conciso dell'uso Callable<Void>
e della restituzione di un null
valore dummy ( ) dal call()
metodo.
Runnable
esiste (in gran parte) per motivi di compatibilità con le versioni precedenti. Ma non ci sono situazioni in cui è inutile o troppo costoso implementare (o richiedere) l' Callable
interfaccia (ad es., In ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
)? Quindi non c'è alcun vantaggio nel mantenere entrambe le interfacce nella lingua, anche se la storia non ha forzato il risultato attuale?
Runnable
sarebbe stato modificato se non ci fosse stato un imperativo per mantenere la compatibilità. La "caldaia" di return null;
è un argomento debole. (Almeno, quella sarebbe stata la mia decisione ... nell'ipotetico contesto in cui potresti ignorare la retrocompatibilità.)
Callable
necessario implementare il call()
metodo mentre è Runnable
necessario implementare il run()
metodo.Callable
può restituire un valore ma Runnable
non può.Callable
può generare un'eccezione controllata ma Runnable
non è possibile.A Callable
può essere usato con ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
metodi ma Runnable
non può essere.
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
Ho trovato questo in un altro blog che può spiegarlo un po 'di più queste differenze :
Sebbene entrambe le interfacce siano implementate dalle classi che desiderano eseguire in un diverso thread di esecuzione, ma ci sono alcune differenze tra le due interfacce che sono:
Callable<V>
esempio restituisce un risultato di tipo V
, mentre Runnable
un'istanza non lo fa.Callable<V>
esempio può lanciare eccezioni controllate, mentre Runnable
un'istanza non puòI progettisti di Java sentivano il bisogno di estendere le capacità Runnable
dell'interfaccia, ma non volevano influenzare gli usi Runnable
dell'interfaccia e probabilmente questo era il motivo per cui avevano scelto un'interfaccia separata chiamata Callable
in Java 1.5 piuttosto che cambiare il già esistente Runnable
.
Vediamo dove si potrebbero usare Runnable e Callable.
Runnable e Callable vengono entrambi eseguiti su un thread diverso rispetto al thread chiamante. Ma Callable può restituire un valore e Runnable non può. Quindi, dove si applica davvero questo.
Runnable : se hai un incendio e dimentica l'attività, usa Runnable. Inserisci il tuo codice in un Runnable e quando viene chiamato il metodo run (), puoi eseguire la tua attività. Al thread chiamante non importa davvero quando si esegue l'attività.
Callable : se si sta tentando di recuperare un valore da un'attività, utilizzare Callable. Ora richiamabile da solo non farà il lavoro. Avrai bisogno di un futuro che avvolgi il tuo Callable e ottenga i tuoi valori su future.get (). Qui il thread chiamante verrà bloccato fino a quando il Future non tornerà con risultati che a loro volta attendono l'esecuzione del metodo call () di Callable.
Pensa quindi a un'interfaccia per una classe di destinazione in cui sono definiti sia i metodi di Runnable che Callable. La classe chiamante chiamerà casualmente i tuoi metodi di interfaccia senza sapere quale sia Runnable e quale sia Callable. I metodi Runnable verranno eseguiti in modo asincrono, fino a quando viene chiamato un metodo Callable. Qui il thread della classe chiamante verrà bloccato poiché stai recuperando valori dalla tua classe target.
NOTA: all'interno della classe target è possibile effettuare chiamate a Callable e Runnable su un singolo esecutore thread, rendendo questo meccanismo simile a una coda di invio seriale. Quindi, fintanto che il chiamante chiama i tuoi metodi avvolti Runnable, il thread chiamante verrà eseguito molto velocemente senza bloccarsi. Non appena chiamerà un metodo chiamato nel metodo Future, dovrà bloccarsi fino a quando tutti gli altri elementi in coda non verranno eseguiti. Solo allora il metodo tornerà con i valori. Questo è un meccanismo di sincronizzazione.
Callable
l'interfaccia dichiara il call()
metodo ed è necessario fornire generici poiché il tipo di Object call () dovrebbe restituire -
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
d'altra parte è l'interfaccia che dichiara il run()
metodo che viene chiamato quando si crea un thread con il runnable e si chiama start () su di esso. Puoi anche chiamare direttamente run () ma che esegue semplicemente il metodo run () è lo stesso 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();
}
Riassumendo alcune notevoli differenze sono
Runnable
oggetto non restituisce un risultato mentre un Callable
oggetto restituisce un risultato.Runnable
oggetto non può generare un'eccezione controllata laddove un Callable
oggetto può generare un'eccezione.Runnable
interfaccia esiste da Java 1.0 mentre è Callable
stata introdotta solo in Java 1.5.Poche somiglianze includono
I metodi nell'interfaccia di ExecutorService sono
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Scopo di queste interfacce dalla documentazione di Oracle:
L' interfaccia eseguibile deve essere implementata da qualsiasi classe le cui istanze devono essere eseguite da a Thread
. La classe deve definire un metodo senza argomenti chiamati run
.
Callable : un'attività che restituisce un risultato e può generare un'eccezione. Gli implementatori definiscono un singolo metodo senza argomenti chiamati call. L' Callable
interfaccia è simile a Runnable
quella in quanto entrambi sono progettati per classi le cui istanze sono potenzialmente eseguite da un altro thread. A Runnable
, tuttavia, non restituisce un risultato e non può generare un'eccezione controllata.
Altre differenze:
Puoi passare Runnable
per creare una discussione . Ma non puoi creare un nuovo thread passando Callable
come parametro. È possibile passare a Callable solo alle ExecutorService
istanze.
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();
}
}
Utilizzare Runnable
per il fuoco e dimenticare le chiamate. Utilizzare Callable
per verificare il risultato.
Callable
può essere passato al metodo invokeAll diversamente dal Runnable
. Metodi invokeAny
ed invokeAll
esecuzione delle forme più comunemente utili di esecuzione in blocco, eseguendo una raccolta di attività e quindi aspettando che almeno una o tutte le operazioni vengano completate
Differenza fondamentale: nome del metodo da implementare => run()
per Runnable
e call()
per Callable
.
Come già menzionato qui, Callable è un'interfaccia relativamente nuova ed è stata introdotta come parte del pacchetto di concorrenza. Sia Callable che Runnable possono essere usati con gli esecutori. Il thread di classe (che implementa Runnable stesso) supporta solo Runnable.
Puoi ancora usare Runnable con gli esecutori. Il vantaggio di Callable è che puoi inviarlo all'esecutore e ottenere immediatamente il risultato futuro che verrà aggiornato al termine dell'esecuzione. Lo stesso può essere implementato con Runnable, ma in questo caso devi gestire i risultati da solo. Ad esempio è possibile creare una coda di risultati che conterrà tutti i risultati. Altre discussioni possono attendere su questa coda e gestire i risultati che arrivano.
Future
o aggiungendo un hook che rileva tutte le eccezioni non rilevate
Thread
a fare un uso significativo Callable
dell'interfaccia in modo che un singolo thread possa essere personalizzato per fare cose richiamabili e altre cose che lo sviluppatore potrebbe desiderare. Se qualcuno che legge questo commento pensa che mi sbaglio, mi piacerebbe saperlo meglio ...
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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 |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
I progettisti di Java sentivano il bisogno di estendere le capacità Runnable
dell'interfaccia, ma non volevano influenzare gli usi Runnable
dell'interfaccia e probabilmente questo era il motivo per cui avevano scelto un'interfaccia separata chiamata Callable
in Java 1.5 piuttosto che cambiare il già Runnable
interfaccia esistente che fa parte di Java da Java 1.0. fonte
Le differenze tra Callable e Runnable sono le seguenti:
Callable e Runnable sono entrambi simili tra loro e possono essere utilizzati nell'implementazione del thread. In caso di implementazione di Runnable è necessario implementare il metodo run () ma in caso di chiamata è necessario implementare il metodo call () , entrambi i metodi funzionano in modo simile ma il metodo call () ha una maggiore flessibilità. Esistono alcune differenze.
Differenza tra eseguibile e richiamabile come di seguito--
1) Il metodo run () di runnable restituisce void , significa che se vuoi che il tuo thread restituisca qualcosa che puoi usare ulteriormente, non hai scelta con il metodo run () Runnable . Esiste una soluzione "Callable" , se si desidera restituire qualsiasi cosa in forma di oggetto, è necessario utilizzare Callable anziché Runnable . L'interfaccia richiamabile ha il metodo 'call ()' che restituisce Object .
Firma del metodo - Eseguibile->
public void run(){}
Callable->
public Object call(){}
2) Nel caso del metodo Run () Runnable se si verifica un'eccezione verificata, è necessario gestirla con try catch block , ma nel caso del metodo Call () Callable è possibile generare l'eccezione controllata come di seguito
public Object call() throws Exception {}
3) Runnable proviene dalla versione java 1.0 legacy , ma callable è arrivato in versione Java 1.5 con framework Executer .
Se hai familiarità con gli Executer , dovresti usare Callable anziché Runnable .
Spero tu capisca.
Runnable (vs) Callable diventa importante quando stiamo usando Executer framework.
ExecutorService è una sottointerfaccia di Executor
, che accetta attività eseguibili e richiamabili.
Il multi-threading precedente può essere ottenuto utilizzando Interface Since 1.0 , ma qui il problema è dopo aver completato l'attività thread non siamo in grado di raccogliere le informazioni sui thread. Al fine di raccogliere i dati possiamo utilizzare i campi statici.Runnable
Esempio Discussioni separate per raccogliere i dati di ogni studente.
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() );
}
Per risolvere questo problema hanno introdotto da 1.5 che restituisce un risultato e può generare un'eccezione.Callable<V>
Metodo astratto singolo : Sia l'interfaccia Callable che Runnable hanno un singolo metodo astratto, il che significa che possono essere utilizzati nelle espressioni lambda in java 8.
public interface Runnable {
public void run();
}
public interface Callable<Object> {
public Object call() throws Exception;
}
Esistono diversi modi per delegare le attività per l'esecuzione a un ExecutorService .
execute(Runnable task):void
crea un nuovo thread ma non blocca il thread principale o il thread del chiamante poiché questo metodo restituisce void.submit(Callable<?>):Future<?>
, submit(Runnable):Future<?>
crea nuovo thread e blocca il thread principale quando si utilizza future.get () .Esempio di utilizzo di interfacce eseguibili, richiamabili con framework Executor.
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();
}
}
È una specie di convenzione di denominazione dell'interfaccia che si abbina alla programmazione funzionale
//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 Throwable;
}
...