В чем разница между использованием интерфейсов Runnable
и Callable
при разработке параллельного потока в Java, почему бы вы выбрали один из других?
Разница между интерфейсами Runnable и Callable в Java
Ответ 1
См. объяснение здесь.
Интерфейс Callable похож на Runnable, в том, что оба предназначены для классов, экземпляры которых потенциально выполненный другим нить. Пробег, однако, не вернуть результат и не может проверенное исключение.
Ответ 2
Каковы различия в приложениях
Runnable
иCallable
. Разница только с возвращаемым параметром, присутствующим вCallable
?
В принципе, да. См. Ответы на этот вопрос. И javadoc для Callable
.
Какая необходимость иметь оба, если
Callable
может делать все, что делаетRunnable
?
Поскольку интерфейс Runnable
не может делать все, что делает Callable
!
Runnable
существует со времен Java 1.0, но Callable
был введен только в Java 1.5... для обработки прецедентов, которые Runnable
не поддерживает. Теоретически команда Java могла бы изменить сигнатуру метода Runnable.run()
, но это нарушило бы бинарную совместимость с кодом pre-1.5, требуя перекодировки при переносе старого кода Java на более новые JVM. Это БОЛЬШОЙ НЕТ-НЕТ. Java стремится к обратной совместимости... и это была одна из самых больших точек продаж в мире для бизнес-вычислений.
И, очевидно, существуют прецеденты, когда задача не должна возвращать результат или бросать проверенное исключение. Для этих прецедентов использование Runnable
более кратким, чем использование Callable<Void>
и возврат значения фиктивного значения (null
) из метода call()
.
Ответ 3
- A
Callable
должен реализовать методcall()
, аRunnable
должен реализовать методrun()
. - A
Callable
может вернуть значение, ноRunnable
не может. - A
Callable
может выставить проверенное исключение, ноRunnable
не может. -
A
Callable
может использоваться с методамиExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
, ноRunnable
не может быть.public interface Runnable { void run(); } public interface Callable<V> { V call() throws Exception; }
Ответ 4
Я нашел это в другом блоге, который может объяснить это немного больше этих различий:
Хотя оба интерфейса реализованы классами, которые хотят выполнить в другом потоке выполнения, но между двумя интерфейсами есть несколько различий:
- Экземпляр
Callable<V>
возвращает результат типаV
, тогда как экземплярRunnable
не работает. - A
Callable<V>
экземпляр может выдавать проверенные исключения, тогда как экземплярRunnable
не может
Разработчики Java почувствовали необходимость расширения возможностей интерфейса Runnable
, но они не хотели влиять на использование интерфейса Runnable
, и, вероятно, именно по этой причине они пошли на то, чтобы иметь отдельный интерфейс с именем Callable
в Java 1.5, чем изменение уже существующего Runnable
.
Ответ 5
Посмотрим, где можно использовать Runnable и Callable.
Runnable и Callable выполняются в другом потоке, чем вызывающий поток. Но Callable может вернуть значение, а Runnable не может. Итак, где это действительно применяется.
Runnable. Если у вас есть задача "Огонь" и "Забыть", используйте Runnable. Поместите свой код внутри Runnable и когда вызывается метод run(), вы можете выполнить свою задачу. Называющий поток действительно не волнует, когда вы выполняете свою задачу.
Вызываемый. Если вы пытаетесь получить значение из задачи, используйте функцию Callable. Теперь вызываемый сам по себе не будет выполнять эту работу. Вам понадобится будущее, которое вы обернете вокруг своего Callable и получите свои ценности в future.get(). Здесь вызывающий поток будет заблокирован до тех пор, пока будущее не вернется с результатами, которые в свою очередь ожидают выполнения метода Callable call().
Итак, подумайте о интерфейсе к целевому классу, где определены оба метода Runnable и Callable wrapped. Вызывающий класс будет случайным образом вызывать ваши методы интерфейса, не зная, что является Runnable и который является Callable. Методы Runnable будут выполняться асинхронно, пока не будет вызван метод Callable. Здесь поток вызывающего класса будет блокироваться, так как вы извлекаете значения из вашего целевого класса.
ПРИМЕЧАНИЕ. Внутри вашего целевого класса вы можете совершать вызовы Callable и Runnable на одном исполнителе потоков, делая этот механизм похожим на очередность последовательной отправки. Таким образом, до тех пор, пока вызывающий вызов вызывает ваши Runnable wrapped methods, вызывающий поток будет выполняться очень быстро, не блокируя. Как только он вызовет Callable, завернутый в метод Future, он будет заблокирован до тех пор, пока не будут выполнены все остальные очереди. Только тогда метод вернется со значениями. Это механизм синхронизации.
Ответ 6
Callable
интерфейс объявляет метод call()
, и вам необходимо предоставить generics, поскольку тип Object Object() должен возвращать -
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
, с другой стороны, это интерфейс, объявляющий метод run()
, который вызывается при создании Thread с runnable и вызовом start() на нем. Вы также можете напрямую вызвать run(), но это просто выполняет метод run() - это тот же поток.
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object
* <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();
}
Подводя итог нескольким заметным различиям,
- Объект
Runnable
не возвращает результат, тогда как объектCallable
возвращает результат. - Объект
Runnable
не может выставить проверенное исключение, если объектCallable
может исключение. - Интерфейс
Runnable
существует уже с Java 1.0, тогда какCallable
был введен только в Java 1.5.
Немногие сходства включают
- Экземпляры классов, реализующих интерфейсы Runnable или Callable, потенциально выполненный другим потоком.
- Экземпляр интерфейсов Callable и Runnable может быть выполнен ExecutorService с помощью метода submit().
- Оба являются функциональными интерфейсами и могут использоваться в выражениях лямбда с Java8.
Способы в интерфейсе ExecutorService
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Ответ 7
Назначение этих интерфейсов из документации Oracle:
Выполняемый интерфейс должен быть реализован любым классом, экземпляры которого предназначены для выполнения Thread
. Класс должен определять метод без аргументов, который называется run
.
Callable: задача, которая возвращает результат и может вызвать исключение. Реализаторы определяют один метод без аргументов, называемый call. Интерфейс Callable
похож на Runnable
в том, что оба предназначены для классов, чьи экземпляры потенциально выполняются другим потоком. Runnable
, однако, не возвращает результат и не может выдать проверенное исключение.
Другие отличия:
-
Вы можете передать
Runnable
для создания потока. Но вы не можете создать новыйCallable
передавCallable
качестве параметра. Вы можете передать Callable только экземплярамExecutorService
.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(); } }
-
Используйте
Runnable
для огня и забывайте звонки. ИспользуйтеCallable
чтобы проверить результат. -
Callable
может быть передан в метод invokeAll в отличие отRunnable
. МетодыinvokeAny
иinvokeAll
выполняют наиболее часто используемые формы массового выполнения, выполняя набор задач и ожидая завершения хотя бы одной или всех задач. -
Тривиальная разница: имя метода для реализации =>
run()
дляRunnable
иcall()
дляCallable
.
Ответ 8
Как уже упоминалось, Callable является относительно новым интерфейсом, и он был представлен как часть пакета concurrency. Оба Callable и Runnable могут использоваться с исполнителями. Класс Thread (который реализует Runnable) поддерживает только Runnable.
Вы можете использовать Runnable с исполнителями. Преимущество Callable в том, что вы можете отправить его исполнителю и сразу же получить обратно. Результат в будущем, который будет обновлен после завершения выполнения. То же самое можно реализовать с помощью Runnable, но в этом случае вам нужно самостоятельно управлять результатами. Например, вы можете создать очередь результатов, которая будет содержать все результаты. Другой поток может ждать в этой очереди и обрабатывать результаты, которые приходят.
Ответ 9
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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 |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
Разработчики Java чувствовали необходимость расширения возможностей интерфейса Runnable
, но они не хотели влиять на использование интерфейса Runnable
и, возможно, именно поэтому они Callable
отдельный интерфейс с именем Callable
в Java 1.5, чем изменение уже существующего интерфейса Runnable
который был частью Java начиная с Java 1.0. источник
Ответ 10
Разница между Callable и Runnable заключается в следующем:
- Callable представлен в JDK 5.0, а Runnable представлен в JDK 1.0
- У Callable есть метод call(), но у Runnable есть метод run().
- У Callable есть метод call, который возвращает значение, но у Runnable есть метод run, который не возвращает никакого значения.
- вызывающий метод может выдать проверенное исключение, но метод run не может выдать проверенное исключение.
- Вызываемое использование метода submit() для помещения в очередь задач, но запускаемое использование метода execute() для помещения в очередь задач.
Ответ 11
Callable и Runnable оба похожи друг на друга и могут использовать в реализации потока. В случае реализации Runnable вы должны реализовать метод run(), но в случае вызываемого необходимо реализовать метод call(), оба метода работают одинаково, но метод вызываемого вызова() обладает большей гибкостью. Между ними есть некоторые различия.
Разница между Runnable и вызываемой как below--
1) Метод run() runnable возвращает void, значит, если вы хотите, чтобы ваш поток возвращал что-то, что вы можете использовать в дальнейшем, тогда у вас нет выбора с методом Runnable run(). Существует решение "Callable". Если вы хотите вернуть какую-либо вещь в виде объекта, вам следует использовать Callable вместо Runnable. В вызываемом интерфейсе есть метод call(), который возвращает Object.
Подпись метода - Runnable->
public void run(){}
Callable->
public Object call(){}
2) В случае использования метода Runnable run(), если возникает какое-либо проверенное исключение, вам необходимо обработать блок try catch, но в случае вызова метода Callable() вы можете выбросить проверенное исключение, как показано ниже
public Object call() throws Exception {}
3) Runnable поставляется с устаревшей версией java 1.0, но функция callable появилась в версии Java 1.5 с платформой Executer.
Если вы знакомы с Executers, вам следует использовать Callable вместо Runnable.
Надеюсь, вы понимаете.
Ответ 12
Runnable (против) Callable вступает в силу, когда мы используем среду исполнения.
ExecutorService - это подинтерфейс Executor
, который принимает задачи Runnable и Callable.
Раньше многопоточности можно было достичь с помощью интерфейса Runnable
начиная с версии 1.0 но здесь проблема в том, что после завершения задачи потока мы не можем собрать информацию о потоках. Для сбора данных мы можем использовать статические поля.
Пример Отдельные темы для сбора данных о каждом ученике.
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() );
}
Чтобы решить эту проблему, они ввели Callable<V>
начиная с 1.5, который возвращает результат и может вызвать исключение.
-
Единый абстрактный метод. Интерфейсы Callable и Runnable имеют один абстрактный метод, что означает, что они могут использоваться в лямбда-выражениях в Java 8.
public interface Runnable { public void run(); } public interface Callable<Object> { public Object call() throws Exception; }
Есть несколько различных способов делегировать задачи для выполнения в ExecutorService.
-
execute(Runnable task):void
создает новый поток, но не блокирует основной поток или поток вызывающего, так как этот метод возвращает void. -
submit(Callable<?>):Future<?>
,submit(Runnable):Future<?>
создает новый поток и блокирует основной поток при использовании future.get().
Пример использования интерфейсов Runnable, Callable с платформой 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();
}
}