Разница между интерфейсами Runnable и Callable в Java
492
В чем разница между использованием Runnableи Callableинтерфейсов при проектировании одновременных потоков в Java, почему бы вы выбрали один над другим?
Интерфейс Callable похож на Runnable в том, что оба предназначены для классов, чьи экземпляры потенциально выполняются другим потоком. Runnable, однако, не возвращает результат и не может вызвать проверенное исключение.
Зачем нужны оба, если Callableможно сделать все, что Runnableделает?
Потому что Runnableинтерфейс не может делать все, что Callableделает!
Runnableсуществует с Java 1.0, но Callableбыл представлен только в Java 1.5 ... для обработки сценариев использования, которые Runnableне поддерживают. Теоретически, команда Java могла бы изменить сигнатуру Runnable.run()метода, но это нарушило бы двоичную совместимость с кодом до 1.5, что потребовало бы перекодирования при переносе старого кода Java в более новые JVM. Это БОЛЬШОЕ НЕТ-НЕТ. Java стремится быть обратно совместимым ... и это было одним из самых значительных преимуществ Java для бизнес-вычислений.
И, очевидно, есть варианты использования, когда задача не должна возвращать результат или выдавать проверенное исключение. В этих случаях использование Runnableболее кратко, чем использование Callable<Void>и возврат значения dummy ( null) из call()метода.
Интересно, откуда вы взяли эту историю? Это очень полезно.
Человек-паук
4
@prash - основные факты можно найти в старых учебниках. Как и первое издание Java в двух словах.
Стивен С.
4
(@prash - Также ... начав использовать Java в эпоху Java 1.1.)
Стивен С.
1
@ StephhenC Если я правильно прочитал ваш ответ, вы предполагаете, что он Runnableсуществует (в основном) по причинам обратной совместимости. Но не бывает ли ситуаций, когда нет необходимости или слишком дорого реализовывать (или требовать) Callableинтерфейс (например, в ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit))? Так разве не выгодно поддерживать оба интерфейса в языке, даже если история не вызвала текущий результат?
максимум
1
@max - Ну, я сказал это, и я все еще согласен с этим. Однако это вторичная причина. Но даже в этом случае, я подозреваю, что Runnableэто было бы изменено, если бы не было необходимости поддерживать совместимость. «Образец» return null;- слабый аргумент. (По крайней мере, это было бы мое решение ... в гипотетическом контексте, где вы могли бы игнорировать обратную совместимость.)
Стивен С.
82
CallableНеобходимо реализовать call()метод в то время как Runnableнеобходимо реализовать run()метод.
A Callableможет вернуть значение, но Runnableне может.
CallableМожет бросить проверяемое исключение , но Runnableне может.
A Callableможет использоваться с ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)методами, но Runnableне может быть.
publicinterfaceRunnable{void run();}publicinterfaceCallable<V>{
V call()throwsException;}
ExecutorService.submit (Runnable task) также существует и очень полезен
Яир Кукелька
Runnable также можно использовать с ExecutorService следующими способами: 1) ExecutorService.execute (Runnable) 2) ExecutorService.submit (Runnable)
Азам Хан
2
Также есть Executor.submit (Callable <T> задача), но вы не можете вызывать All или invokeAny с коллекцией Runnable задач Collection <? расширяет Callable <T >> задач
Никли
36
Я нашел это в другом блоге, который может объяснить немного больше этих различий :
Хотя оба интерфейса реализованы классами, которые хотят выполнять в другом потоке выполнения, между этими двумя интерфейсами есть несколько отличий:
Callable<V>Экземпляр возвращает результат типа V, в то время как Runnableэкземпляр не делает.
Callable<V>Экземпляр может бросить проверенные исключения, в то время как Runnableэкземпляр не может
Разработчики Java чувствовали необходимость расширения возможностей Runnableинтерфейса, но они не хотели влиять на использование Runnableинтерфейса, и, вероятно, именно поэтому они решили использовать отдельный интерфейс с именем Callableв Java 1.5, а не изменять уже существующий интерфейс. существующий Runnable.
Давайте посмотрим, где можно использовать Runnable и Callable.
Runnable и Callable работают в другом потоке, чем в вызывающем потоке. Но Callable может вернуть значение, а Runnable не может. Так, где это действительно применяется.
Runnable : если у вас есть задание на запуск и забытие, используйте Runnable. Поместите свой код в Runnable, и когда вызывается метод run (), вы можете выполнить свою задачу. Вызывающему потоку действительно все равно, когда вы выполняете свою задачу.
Callable : если вы пытаетесь получить значение из задачи, используйте Callable. Теперь вызываемый сам по себе не сделает работу. Вам понадобится Future, который вы оберните вокруг своего Callable и получите свои значения в future.get (). Здесь вызывающий поток будет заблокирован, пока Future не вернется с результатами, которые, в свою очередь, ожидают выполнения метода call () Callable.
Так что подумайте об интерфейсе с целевым классом, в котором определены как упакованные методы Runnable, так и Callable. Вызывающий класс будет случайным образом вызывать методы вашего интерфейса, не зная, какой из них Runnable, а какой - Callable. Методы Runnable будут выполняться асинхронно, пока не будет вызван метод Callable. Здесь поток вызывающего класса будет блокироваться, поскольку вы извлекаете значения из целевого класса.
ПРИМЕЧАНИЕ. Внутри целевого класса вы можете выполнять вызовы Callable и Runnable в одном потоке-исполнителе, что делает этот механизм похожим на очередь последовательной отправки. Поэтому до тех пор, пока вызывающая сторона вызывает ваши упакованные методы Runnable, вызывающий поток будет выполняться очень быстро без блокировки. Как только он вызывает Callable, обернутый в метод Future, он должен блокироваться, пока не будут выполнены все остальные элементы в очереди. Только тогда метод вернется со значениями. Это механизм синхронизации.
CallableИнтерфейс объявляет call()метод, и вы должны предоставить обобщенные значения, так как тип вызова объекта () должен возвращаться -
publicinterfaceCallable<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()throwsException;}
Runnableс другой стороны, это интерфейс, который объявляет run()метод, который вызывается при создании потока с runnable и вызовом start (). Вы также можете напрямую вызвать run (), но он просто выполняет метод run () в том же потоке.
publicinterfaceRunnable{/**
* 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()
*/publicabstractvoid 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);
Назначение этих интерфейсов из документации Oracle:
Выполняемый интерфейс должен быть реализован любым классом, экземпляры которого предназначены для выполнения Thread. Класс должен определять метод без вызываемых аргументов run.
Callable : задача, которая возвращает результат и может вызвать исключение. Реализаторы определяют один метод без аргументов, называемый call. CallableИнтерфейс аналогичен Runnable, в том , что оба они предназначены для классов, экземпляры потенциально выполняется в другом потоке. Однако A Runnableне возвращает результат и не может выдать проверенное исключение.
Другие отличия:
Вы можете перейти Runnableк созданию темы . Но вы не можете создать новый поток, передавая в Callableкачестве параметра. Вы можете передать Callable только ExecutorServiceэкземплярам.
publicclassHelloRunnableimplementsRunnable{publicvoid run(){System.out.println("Hello from a thread!");}publicstaticvoid main(String args[]){(newThread(newHelloRunnable())).start();}}
Используйте Runnableдля огня и забудьте звонки. Используйте Callableдля проверки результата.
Callableможет быть передан в метод invokeAll в отличие от Runnable. Методы invokeAnyи invokeAllвыполнение наиболее часто используемых форм массового выполнения, выполнение набора задач и ожидание завершения хотя бы одной или всех задач.
Тривиальная разница: имя метода для реализации => run()для Runnableи call()для Callable.
Как уже упоминалось, Callable - это относительно новый интерфейс, который был представлен как часть пакета для параллелизма. И Callable, и Runnable могут быть использованы с исполнителями. Класс Thread (который реализует сам Runnable) поддерживает только Runnable.
Вы все еще можете использовать Runnable с исполнителями. Преимущество Callable в том, что вы можете отправить его исполнителю и сразу же получить результат в будущем, который будет обновлен после завершения выполнения. То же самое может быть реализовано с помощью Runnable, но в этом случае вам придется управлять результатами самостоятельно. Например, вы можете создать очередь результатов, которая будет содержать все результаты. Другой поток может ждать в этой очереди и обрабатывать результаты, которые поступают.
Интересно, каков пример потока, выбрасывающего исключение в Java? сможет ли основной поток перехватить это исключение? Если нет, я бы не использовал Callable. Алекс, у тебя есть какое-то понимание этого? Спасибо!
триллионы
1
Код, выполняемый в пользовательском потоке, как и любой другой код, может выдать исключение. Чтобы перехватить его в другом потоке, вы должны приложить некоторые усилия либо с помощью пользовательского механизма уведомлений (например, на основе слушателей), либо с помощью Futureили добавив ловушку, которая перехватывает все непроигранные исключения: docs.oracle.com/javase/6/docs/api/ java / lang /…
AlexR
Отличная информация! Спасибо, Алекс! :)
триллионы
1
Я проголосовал за этот ответ, потому что он утверждает (правильно, если принимать по номиналу), нужно использовать модель пула потоков с вызываемыми объектами. По-видимому, в этом заключается и то, что нельзя расширять Threadвозможности осмысленного использования Callableинтерфейса, чтобы можно было настроить один поток для выполнения вызываемых вещей и других вещей, которые мог бы пожелать разработчик. Если кто-то, кто читает этот комментарий, думает, что я неправ, я хотел бы знать лучше ...
8
+-------------------------------------+--------------------------------------------------------------------------------------------------+|Runnable|Callable<T>|+-------------------------------------+--------------------------------------------------------------------------------------------------+|Introduced in Java1.0 of java.lang |Introduced in Java1.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 throwCheckedExceptions|CanthrowCheckedExceptions|+-------------------------------------+--------------------------------------------------------------------------------------------------+
Разработчики Java чувствовали необходимость расширения возможностей Runnableинтерфейса, но они не хотели влиять на использование Runnableинтерфейса, и, вероятно, именно поэтому они решили использовать отдельный интерфейс с именем Callableв Java 1.5, а не изменять уже существующий интерфейс. существующий Runnableинтерфейс, который был частью Java с Java 1.0. источник
Важно подчеркнуть, что проверено исключение , а не RuntimeException
BertKing
5
Callable и Runnable оба похожи друг на друга и могут использовать в реализации потока. В случае реализации Runnable вы должны реализовать метод run (), но в случае вызываемого вы должны реализовать метод call () , оба метода работают одинаково, но метод вызываемого вызова () обладает большей гибкостью. Между ними есть некоторые различия.
Разница между Runnable и вызываемым , как below--
1) Run () метод работоспособных возвращает недействительных , средства , если вы хотите , чтобы ваш обратный поток то , что вы можете использовать в дальнейшем , то у вас нет иного выбора , с Runnable Run () метод. Существует решение «Callable». Если вы хотите вернуть какую-либо вещь в виде объекта, вам следует использовать Callable вместо Runnable . В вызываемом интерфейсе есть метод call (), который возвращает Object .
Подпись метода - Runnable->
publicvoid run(){}
Callable->
publicObject call(){}
2) В случае метода Runnable run (), если возникает какое-либо проверенное исключение, вам необходимо обработать блок try catch , но в случае вызова метода Callable () вы можете выбросить проверенное исключение, как показано ниже
publicObject call()throwsException{}
3) Runnable поставляется с устаревшей версией java 1.0 , но функция callable появилась в версии Java 1.5 с платформой Executer .
Если вы знакомы с Executers, вам следует использовать Callable вместо Runnable .
Runnable (против) Callable вступает в силу, когда мы используем среду исполнения.
ExecutorService - это подинтерфейс Executor, который принимает задачи Runnable и Callable.
Раньше многопоточности можно было достичь с помощью интерфейса начиная с версии 1.0 , но здесь проблема в том, что после завершения задачи потока мы не можем собрать информацию о потоках. Для сбора данных мы можем использовать статические поля.Runnable
Пример Отдельные темы для сбора данных о каждом ученике.
staticHashMap<String,List> multiTasksData =newHashMap();publicstaticvoid main(String[] args){Thread t1 =newThread(newRunnableImpl(1),"T1");Thread t2 =newThread(newRunnableImpl(2),"T2");Thread t3 =newThread(newRunnableImpl(3),"T3");
multiTasksData.put("T1",newArrayList());// later get the value and update it.
multiTasksData.put("T2",newArrayList());
multiTasksData.put("T3",newArrayList());}
Чтобы решить эту проблему, они внедрили начиная с версии 1.5, которая возвращает результат и может вызвать исключение.Callable<V>
Единый абстрактный метод . Интерфейсы Callable и Runnable имеют один абстрактный метод, что означает, что они могут использоваться в лямбда-выражениях в Java 8.
Ответы:
Смотрите объяснение здесь .
источник
В основном да. Смотрите ответы на этот вопрос . И то, что для Javadoc
Callable
.Потому что
Runnable
интерфейс не может делать все, чтоCallable
делает!Runnable
существует с Java 1.0, ноCallable
был представлен только в Java 1.5 ... для обработки сценариев использования, которыеRunnable
не поддерживают. Теоретически, команда Java могла бы изменить сигнатуруRunnable.run()
метода, но это нарушило бы двоичную совместимость с кодом до 1.5, что потребовало бы перекодирования при переносе старого кода Java в более новые JVM. Это БОЛЬШОЕ НЕТ-НЕТ. Java стремится быть обратно совместимым ... и это было одним из самых значительных преимуществ Java для бизнес-вычислений.И, очевидно, есть варианты использования, когда задача не должна возвращать результат или выдавать проверенное исключение. В этих случаях использование
Runnable
более кратко, чем использованиеCallable<Void>
и возврат значения dummy (null
) изcall()
метода.источник
Runnable
существует (в основном) по причинам обратной совместимости. Но не бывает ли ситуаций, когда нет необходимости или слишком дорого реализовывать (или требовать)Callable
интерфейс (например, вScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
)? Так разве не выгодно поддерживать оба интерфейса в языке, даже если история не вызвала текущий результат?Runnable
это было бы изменено, если бы не было необходимости поддерживать совместимость. «Образец»return null;
- слабый аргумент. (По крайней мере, это было бы мое решение ... в гипотетическом контексте, где вы могли бы игнорировать обратную совместимость.)Callable
Необходимо реализоватьcall()
метод в то время какRunnable
необходимо реализоватьrun()
метод.Callable
может вернуть значение, ноRunnable
не может.Callable
Может бросить проверяемое исключение , ноRunnable
не может.A
Callable
может использоваться сExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
методами, ноRunnable
не может быть.источник
Я нашел это в другом блоге, который может объяснить немного больше этих различий :
Хотя оба интерфейса реализованы классами, которые хотят выполнять в другом потоке выполнения, между этими двумя интерфейсами есть несколько отличий:
Callable<V>
Экземпляр возвращает результат типаV
, в то время какRunnable
экземпляр не делает.Callable<V>
Экземпляр может бросить проверенные исключения, в то время какRunnable
экземпляр не можетРазработчики Java чувствовали необходимость расширения возможностей
Runnable
интерфейса, но они не хотели влиять на использованиеRunnable
интерфейса, и, вероятно, именно поэтому они решили использовать отдельный интерфейс с именемCallable
в Java 1.5, а не изменять уже существующий интерфейс. существующийRunnable
.источник
Давайте посмотрим, где можно использовать Runnable и Callable.
Runnable и Callable работают в другом потоке, чем в вызывающем потоке. Но Callable может вернуть значение, а Runnable не может. Так, где это действительно применяется.
Runnable : если у вас есть задание на запуск и забытие, используйте Runnable. Поместите свой код в Runnable, и когда вызывается метод run (), вы можете выполнить свою задачу. Вызывающему потоку действительно все равно, когда вы выполняете свою задачу.
Callable : если вы пытаетесь получить значение из задачи, используйте Callable. Теперь вызываемый сам по себе не сделает работу. Вам понадобится Future, который вы оберните вокруг своего Callable и получите свои значения в future.get (). Здесь вызывающий поток будет заблокирован, пока Future не вернется с результатами, которые, в свою очередь, ожидают выполнения метода call () Callable.
Так что подумайте об интерфейсе с целевым классом, в котором определены как упакованные методы Runnable, так и Callable. Вызывающий класс будет случайным образом вызывать методы вашего интерфейса, не зная, какой из них Runnable, а какой - Callable. Методы Runnable будут выполняться асинхронно, пока не будет вызван метод Callable. Здесь поток вызывающего класса будет блокироваться, поскольку вы извлекаете значения из целевого класса.
ПРИМЕЧАНИЕ. Внутри целевого класса вы можете выполнять вызовы Callable и Runnable в одном потоке-исполнителе, что делает этот механизм похожим на очередь последовательной отправки. Поэтому до тех пор, пока вызывающая сторона вызывает ваши упакованные методы Runnable, вызывающий поток будет выполняться очень быстро без блокировки. Как только он вызывает Callable, обернутый в метод Future, он должен блокироваться, пока не будут выполнены все остальные элементы в очереди. Только тогда метод вернется со значениями. Это механизм синхронизации.
источник
Callable
Интерфейс объявляетcall()
метод, и вы должны предоставить обобщенные значения, так как тип вызова объекта () должен возвращаться -Runnable
с другой стороны, это интерфейс, который объявляетrun()
метод, который вызывается при создании потока с runnable и вызовом start (). Вы также можете напрямую вызвать run (), но он просто выполняет метод run () в том же потоке.Подводя итог несколько заметных различий
Runnable
Объект не возвращает результат , тогда какCallable
объект возвращает результат.Runnable
Объект не может бросить проверяемое исключение Тогда какCallable
объект может вызвать исключение.Runnable
Интерфейс был примерно с Java 1.0 , тогда какCallable
был введен только в Java 1.5.Немного сходств включают
Методы в интерфейсе ExecutorService являются
источник
Назначение этих интерфейсов из документации Oracle:
Выполняемый интерфейс должен быть реализован любым классом, экземпляры которого предназначены для выполнения
Thread
. Класс должен определять метод без вызываемых аргументовrun
.Callable : задача, которая возвращает результат и может вызвать исключение. Реализаторы определяют один метод без аргументов, называемый call.
Callable
Интерфейс аналогиченRunnable
, в том , что оба они предназначены для классов, экземпляры потенциально выполняется в другом потоке. Однако ARunnable
не возвращает результат и не может выдать проверенное исключение.Другие отличия:
Вы можете перейти
Runnable
к созданию темы . Но вы не можете создать новый поток, передавая вCallable
качестве параметра. Вы можете передать Callable толькоExecutorService
экземплярам.Пример:
Используйте
Runnable
для огня и забудьте звонки. ИспользуйтеCallable
для проверки результата.Callable
может быть передан в метод invokeAll в отличие отRunnable
. МетодыinvokeAny
иinvokeAll
выполнение наиболее часто используемых форм массового выполнения, выполнение набора задач и ожидание завершения хотя бы одной или всех задач.Тривиальная разница: имя метода для реализации =>
run()
дляRunnable
иcall()
дляCallable
.источник
Как уже упоминалось, Callable - это относительно новый интерфейс, который был представлен как часть пакета для параллелизма. И Callable, и Runnable могут быть использованы с исполнителями. Класс Thread (который реализует сам Runnable) поддерживает только Runnable.
Вы все еще можете использовать Runnable с исполнителями. Преимущество Callable в том, что вы можете отправить его исполнителю и сразу же получить результат в будущем, который будет обновлен после завершения выполнения. То же самое может быть реализовано с помощью Runnable, но в этом случае вам придется управлять результатами самостоятельно. Например, вы можете создать очередь результатов, которая будет содержать все результаты. Другой поток может ждать в этой очереди и обрабатывать результаты, которые поступают.
источник
Future
или добавив ловушку, которая перехватывает все непроигранные исключения: docs.oracle.com/javase/6/docs/api/ java / lang /…Thread
возможности осмысленного использованияCallable
интерфейса, чтобы можно было настроить один поток для выполнения вызываемых вещей и других вещей, которые мог бы пожелать разработчик. Если кто-то, кто читает этот комментарий, думает, что я неправ, я хотел бы знать лучше ...Разработчики Java чувствовали необходимость расширения возможностей
Runnable
интерфейса, но они не хотели влиять на использованиеRunnable
интерфейса, и, вероятно, именно поэтому они решили использовать отдельный интерфейс с именемCallable
в Java 1.5, а не изменять уже существующий интерфейс. существующийRunnable
интерфейс, который был частью Java с Java 1.0. источникисточник
Разница между Callable и Runnable заключается в следующем:
источник
Callable и Runnable оба похожи друг на друга и могут использовать в реализации потока. В случае реализации Runnable вы должны реализовать метод run (), но в случае вызываемого вы должны реализовать метод call () , оба метода работают одинаково, но метод вызываемого вызова () обладает большей гибкостью. Между ними есть некоторые различия.
Разница между Runnable и вызываемым , как below--
1) Run () метод работоспособных возвращает недействительных , средства , если вы хотите , чтобы ваш обратный поток то , что вы можете использовать в дальнейшем , то у вас нет иного выбора , с Runnable Run () метод. Существует решение «Callable». Если вы хотите вернуть какую-либо вещь в виде объекта, вам следует использовать Callable вместо Runnable . В вызываемом интерфейсе есть метод call (), который возвращает Object .
Подпись метода - Runnable->
Callable->
2) В случае метода Runnable run (), если возникает какое-либо проверенное исключение, вам необходимо обработать блок try catch , но в случае вызова метода Callable () вы можете выбросить проверенное исключение, как показано ниже
3) Runnable поставляется с устаревшей версией java 1.0 , но функция callable появилась в версии Java 1.5 с платформой Executer .
Если вы знакомы с Executers, вам следует использовать Callable вместо Runnable .
Надеюсь, вы понимаете.
источник
Runnable (против) Callable вступает в силу, когда мы используем среду исполнения.
ExecutorService - это подинтерфейс
Executor
, который принимает задачи Runnable и Callable.Раньше многопоточности можно было достичь с помощью интерфейса начиная с версии 1.0 , но здесь проблема в том, что после завершения задачи потока мы не можем собрать информацию о потоках. Для сбора данных мы можем использовать статические поля.
Runnable
Пример Отдельные темы для сбора данных о каждом ученике.
Чтобы решить эту проблему, они внедрили начиная с версии 1.5, которая возвращает результат и может вызвать исключение.
Callable<V>
Единый абстрактный метод . Интерфейсы Callable и Runnable имеют один абстрактный метод, что означает, что они могут использоваться в лямбда-выражениях в Java 8.
Есть несколько различных способов делегировать задачи для выполнения в ExecutorService .
execute(Runnable task):void
создает новый поток, но не блокирует основной поток или поток вызывающего, так как этот метод возвращает void.submit(Callable<?>):Future<?>
,submit(Runnable):Future<?>
Ящики новую нить и блоки основной нити при использовании future.get () .Пример использования интерфейсов Runnable, Callable с платформой Executor.
источник
Это своего рода соглашение об именах интерфейсов, которое соответствует функциональному программированию.
источник