Qual é a diferença entre usar as interfaces Runnable
e Callable
ao projetar um encadeamento simultâneo em Java, por que você escolheria um sobre o outro?
Qual é a diferença entre usar as interfaces Runnable
e Callable
ao projetar um encadeamento simultâneo em Java, por que você escolheria um sobre o outro?
Respostas:
Veja a explicação aqui .
A interface Callable é semelhante ao Runnable, pois ambas são projetadas para classes cujas instâncias são potencialmente executadas por outro thread. Um Runnable, no entanto, não retorna um resultado e não pode gerar uma exceção verificada.
Quais são as diferenças nas aplicações de
Runnable
eCallable
. A diferença é apenas com o parâmetro de retorno presente emCallable
?
Basicamente sim. Veja as respostas para esta pergunta . E o javadoc paraCallable
.
Qual é a necessidade de ter os dois se
Callable
pode fazer tudo o queRunnable
faz?
Porque a Runnable
interface não pode fazer tudo o que Callable
faz!
Runnable
existe desde o Java 1.0, mas Callable
foi introduzido apenas no Java 1.5 ... para lidar com casos de uso que Runnable
não suportam. Em teoria, a equipe Java poderia ter alterado a assinatura do Runnable.run()
método, mas isso quebraria a compatibilidade binária com o código anterior à 1.5, exigindo recodificação ao migrar o código Java antigo para as JVMs mais recentes. Isso é um GRANDE NÃO-NÃO. O Java se esforça para ser compatível com versões anteriores ... e esse tem sido um dos maiores pontos de venda do Java para computação comercial.
E, obviamente, existem casos de uso em que uma tarefa não precisa retornar um resultado ou lançar uma exceção verificada. Para esses casos de uso, usar Runnable
é mais conciso do que usar Callable<Void>
e retornar um null
valor dummy ( ) do call()
método
Runnable
existe (em grande parte) por motivos de compatibilidade com versões anteriores. Mas não há situações em que é desnecessário ou muito caro implementar (ou exigir) Callable
interface (por exemplo, in ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
)? Portanto, não há um benefício em manter as duas interfaces no idioma, mesmo que a história não force o resultado atual?
Runnable
teria sido modificado se não houvesse um imperativo para manter a compatibilidade. O "clichê" de return null;
é um argumento fraco. (Pelo menos, essa teria sido a minha decisão ... no contexto hipotético onde você poderia ignorar compatibilidade com versões anteriores.)
Callable
precisa implementar o call()
método enquanto outro Runnable
precisa implementar o run()
método.Callable
pode retornar um valor, mas Runnable
não pode.Callable
pode lançar exceção marcada, mas um Runnable
não pode.A Callable
pode ser usado com ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
métodos, mas a Runnable
não pode ser.
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
Encontrei isso em outro blog que pode explicar um pouco mais essas diferenças :
Embora ambas as interfaces sejam implementadas pelas classes que desejam executar em um encadeamento de execução diferente, existem poucas diferenças entre as duas interfaces:
Callable<V>
instância retorna um resultado do tipo V
, enquanto uma Runnable
instância não.Callable<V>
instância pode gerar exceções verificadas, enquanto uma Runnable
instância não podeOs designers de Java sentiram a necessidade de estender os recursos da Runnable
interface, mas não queriam afetar os usos da Runnable
interface e provavelmente essa foi a razão pela qual eles optaram por ter uma interface separada nomeada Callable
no Java 1.5 do que alterar o já existente Runnable
.
Vejamos onde alguém usaria Runnable e Callable.
Runnable e Callable são executados em um thread diferente do thread de chamada. Mas Callable pode retornar um valor e Runnable não. Então, onde isso realmente se aplica.
Runnable : Se você tiver uma tarefa de ignorar e esquecer, use Runnable. Coloque seu código dentro de um Runnable e, quando o método run () for chamado, você poderá executar sua tarefa. O segmento de chamada realmente não se importa quando você executa sua tarefa.
Chamada : Se você estiver tentando recuperar um valor de uma tarefa, use Chamada. Agora que pode ser chamado por si só não fará o trabalho. Você precisará de um futuro que envolva seu Callable e obtenha seus valores em future.get (). Aqui, o encadeamento de chamada será bloqueado até que o futuro volte com resultados que, por sua vez, aguardam a execução do método call () de Callable.
Portanto, pense em uma interface para uma classe de destino em que você tenha os métodos agrupados Runnable e Callable definidos. A classe de chamada aleatoriamente chamará os métodos da interface sem saber qual é Runnable e qual é Callable. Os métodos Runnable serão executados de forma assíncrona, até que um método Callable seja chamado. Aqui, o encadeamento da classe de chamada será bloqueado, pois você está recuperando valores da sua classe de destino.
NOTA: Dentro da classe de destino, você pode fazer chamadas para Callable e Runnable em um único executor de encadeamento, tornando esse mecanismo semelhante a uma fila de despacho serial. Desde que o chamador chame seus métodos agrupados Runnable, o thread de chamada será executado muito rápido, sem bloquear. Assim que chamar um método Callable envolvido no futuro, ele deverá ser bloqueado até que todos os outros itens na fila sejam executados. Somente então o método retornará com valores. Este é um mecanismo de sincronização.
Callable
interface declara call()
método e você precisa fornecer genéricos, pois o tipo de chamada de objeto () deve retornar -
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
por outro lado, é a interface que declara o run()
método chamado quando você cria um Thread com o executável e chama start (). Você também pode chamar diretamente run (), mas que apenas executa o método run () é o mesmo encadeamento.
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();
}
Para resumir algumas diferenças notáveis são
Runnable
objeto não retorna um resultado, enquanto um Callable
objeto retorna um resultado.Runnable
objeto não pode lançar uma exceção marcada, enquanto um Callable
objeto pode lançar uma exceção.Runnable
interface existe desde o Java 1.0, enquanto Callable
foi introduzida apenas no Java 1.5.Poucas semelhanças incluem
Os métodos na interface ExecutorService são
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Objetivo dessas interfaces da documentação da Oracle:
A interface executável deve ser implementada por qualquer classe cujas instâncias sejam executadas por a Thread
. A classe deve definir um método sem argumentos chamados run
.
Callable : uma tarefa que retorna um resultado e pode gerar uma exceção. Os implementadores definem um único método sem argumentos chamados de chamada. A Callable
interface é semelhante Runnable
, pois ambas são projetadas para classes cujas instâncias são potencialmente executadas por outro encadeamento. UMARunnable
, no entanto, não retorna um resultado e não pode gerar uma exceção verificada.
Outras diferenças:
Você pode passar Runnable
para criar um Thread . Mas você não pode criar um novo thread passando Callable
como parâmetro. Você pode passar Callable apenas para ExecutorService
instâncias.
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();
}
}
Use Runnable
para fogo e esqueça as chamadas. Use Callable
para verificar o resultado.
Callable
pode ser passado para invokeAll método diferente Runnable
. Métodos invokeAny
e invokeAll
execute as formas mais úteis de execução em massa, executando uma coleção de tarefas e aguardando pelo menos uma, ou todas, para concluir
Diferença trivial: nome do método a ser implementado => run()
para Runnable
e call()
para Callable
.
Como já foi mencionado aqui, Callable é uma interface relativamente nova e foi introduzida como parte do pacote de simultaneidade. Callable e Runnable podem ser usados com executores. O thread de classe (que implementa o próprio Runnable) oferece suporte apenas ao Runnable.
Você ainda pode usar o Runnable com executores. A vantagem do Callable é que você pode enviá-lo ao executor e retornar imediatamente o resultado futuro que será atualizado quando a execução for concluída. O mesmo pode ser implementado com o Runnable, mas nesse caso você precisa gerenciar os resultados sozinho. Por exemplo, você pode criar uma fila de resultados que conterá todos os resultados. Outro encadeamento pode esperar nessa fila e lidar com os resultados que chegarem.
Future
ou adicionando gancho que captura todas as exceções não encontradas: docs.oracle.com/javase/6/docs/api/ java / lang /…
Thread
uso significativo da Callable
interface para que um único encadeamento possa ser personalizado para fazer coisas que podem ser chamadas e outras que o desenvolvedor possa querer. Se qualquer um que lê este comentário pensa que eu estou errado, eu gostaria de conhecer melhor ...
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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 |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
Os designers de Java sentiram a necessidade de estender os recursos da Runnable
interface, mas não queriam afetar os usos da Runnable
interface e provavelmente essa foi a razão pela qual eles optaram por ter uma interface separada nomeada Callable
no Java 1.5 do que alterar o já Runnable
interface existente que faz parte do Java desde o Java 1.0. fonte
As diferenças entre Callable e Runnable são as seguintes:
Callable e Runnable são semelhantes entre si e podem ser usados na implementação de threads. No caso de implementar o Runnable, você deve implementar o método run () , mas, no caso de callable, deve implementar o método call () , ambos os métodos funcionam de maneira semelhante, mas callable () método tem mais flexibilidade. Existem algumas diferenças entre eles.
Diferença entre Runnable e Callable como abaixo--
1) O método run () de runnable retorna nulo , significa que se você deseja que seu thread retorne algo que possa ser usado mais, então você não tem escolha com o método runnable run () . Existe uma solução 'Callable' . Se você quiser retornar qualquer coisa na forma de objeto , use Callable em vez de Runnable . Interface callable tem o método 'call ()' que retorna Object .
Assinatura do método - Executável->
public void run(){}
Chamadas->
public Object call(){}
2) No caso do método runnable run () , se surgir alguma exceção verificada, você deve precisar lidar com o bloco try catch , mas, no caso do método Callable call () , é possível lançar a exceção verificada conforme abaixo
public Object call() throws Exception {}
3) Runnable vem da versão legada do java 1.0 , mas callable veio na versão Java 1.5 com o Executer estrutura .
Se você estiver familiarizado com Executores , use Callable em vez de Runnable .
Espero que você entenda.
Executável (vs) Callable entra em quando estamos usando a estrutura do Executer.
ExecutorService é uma subinterface de Executor
, que aceita tarefas Runnable e Callable.
O Multi-Threading anterior pode ser alcançado usando a Interface Desde 1.0 , mas aqui o problema ocorre após a conclusão da tarefa de encadeamento, não podemos coletar as informações dos Encadeamentos. Para coletar os dados, podemos usar campos estáticos.Runnable
Exemplo Segmentos separados para coletar os dados de cada aluno.
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() );
}
Para resolver esse problema, eles introduziram o From 1.5, que retorna um resultado e pode gerar uma exceção.Callable<V>
Método abstrato único : As interfaces Callable e Runnable têm um único método abstrato, o que significa que podem ser usadas em expressões lambda no java 8.
public interface Runnable {
public void run();
}
public interface Callable<Object> {
public Object call() throws Exception;
}
Existem algumas maneiras diferentes de delegar tarefas para execução em um ExecutorService .
execute(Runnable task):void
cria novo encadeamento, mas não bloqueia o encadeamento principal ou o chamador, pois esse método retorna nulo.submit(Callable<?>):Future<?>
, submit(Runnable):Future<?>
cria novo encadeamento e bloqueia o encadeamento principal quando você estiver usando future.get () .Exemplo de uso da interface Interfaces executável, configurável com estrutura de 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();
}
}
É um tipo de convenção de nomenclatura de interface que combina com a programação funcional
//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;
}
...