Разница между интерфейсами Runnable и Callable в Java

в чем разница между использованием Runnable и Callable интерфейсы при проектировании параллельных потоков в Java, почему бы вам выбрать один над другим?

11 ответов


см. объяснение здесь.

вызываемый интерфейс похож на Runnable, в том, что оба предназначены для классов, экземпляры которых потенциально исполняется другим нитка. Runnable, однако, не делает возвращает результат и не может бросить отмеченное исключение.


каковы различия в приложениях 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 на более новые JVMs. Это большое НЕТ-НЕТ. Java стремится быть обратно совместимым ... и это была одна из самых больших точек продаж Java для бизнес-вычислений.

и, очевидно, есть случаи использования, когда задача не нужно чтобы вернуть результат или вызвать проверенное исключение. Для этих случаев использования, используя Runnable более кратким, чем при использовании Callable<Void> и возвращение соска (null) значение call() метод.


  • 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;
    }
    

Я нашел это в другом блоге, которая может объяснить это немного больше различия:

хотя оба интерфейса реализованы классами, которые хотят выполнить в другом потоке выполнения, но есть несколько различий между двумя интерфейсами, которые являются:

  • A Callable<V> экземпляр возвращает результат типа V, тогда как Runnable экземпляра нет.
  • A Callable<V> экземпляр может бросить проверено исключения, тогда как Runnable экземпляр не может

дизайнеры Java почувствовали необходимость расширения возможностей Runnable интерфейс, но они не хотели влиять на использование Runnable интерфейс и, вероятно, именно поэтому они пошли на наличие отдельного интерфейса с именем Callable в Java 1.5, чем изменение уже существующего Runnable.


давайте посмотрим, где можно было бы использовать Runnable и Callable.

Runnable и Callable оба работают в другом потоке, чем вызывающий поток. Но Callable может возвращать значение, а Runnable-нет. Итак, где это действительно применимо.

Runnable: если у вас есть огонь и забыть задачу, то используйте Runnable. Поместите свой код в Runnable, и когда вызывается метод run (), вы можете выполнить свою задачу. Вызывающий поток действительно не заботится, когда вы выполняйте свою задачу.

вызвать: если вы пытаетесь получить значение из задачи, используйте Callable. Теперь callable самостоятельно не справится с работой. Вам понадобится будущее, которое вы обернете вокруг своего вызываемого и получите свои ценности в будущем.получить.)( Здесь вызывающий поток будет заблокирован до тех пор, пока будущее не вернется с результатами, которые, в свою очередь, ждут выполнения метода Callable call ().

поэтому подумайте об интерфейсе к целевому классу, где у вас есть определены оба метода Runnable и Callable wrapped. Класс призвание будет случайно вызов методов интерфейса не зная, что Runnable и который является отзывной. Методы Runnable будут выполняться асинхронно, пока вызываемый метод не будет вызван. Здесь поток вызывающего класса будет блокировать так как вы извлекаете значения из целевого класса.

Примечание: внутри вашего целевого класса вы можете совершать вызовы вызываемого и запускаемого на одном исполнителе потока, делая этот механизм подобно очереди последовательной отправки. До тех пор, пока вызывающий абонент вызывает ваши Runnable обернутые методы вызывающий поток будет выполняться очень быстро без блокировки. Как только он вызывает вызываемый метод, обернутый в Future, он должен будет блокировать, пока не будут выполнены все другие элементы очереди. Только тогда метод вернется со значениями. Это механизм синхронизации.


Callable интерфейс объявляет call() метод и вам нужно предоставить дженерики, поскольку тип вызова объекта () должен возвращать -

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() метод, который вызывается при создании потока с 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'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();
}

суммировать несколько заметных различий

  1. A Runnable объект не возвращает результат, тогда как только в Java 1.5.

мало сходства включают

  1. экземпляры классов, реализующих интерфейсы Runnable или Callable, являются потенциально выполняется другим потоком.
  2. экземпляр как вызываемого, так и запускаемого интерфейсов может быть выполнен ExecutorService с помощью метода submit ().
  3. оба являются функциональными интерфейсами и могут использоваться в лямбда-выражениях с Java8.

методы в интерфейсе ExecutorService являются

<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);

назначение этих интерфейсов из документации oracle:

Runnable интерфейс должен быть реализован любым классом, экземпляры которого предназначены, чтобы быть выполненными Thread. Класс должен определить метод без аргументов с именем run.

вызвать: задача, которая возвращает результат и может бросить исключение. Реализаторы определяют один метод без аргументов Call. The Callable интерфейс похож на Runnable, в этом оба предназначены для классов, экземпляры которых потенциально выполняются другим потоком. А Runnable, однако, не возвращает результат и не может выдать проверенное исключение.

другие отличия:

  1. вы можете пройти Runnable создать нить. Но вы не можете создать новый поток, передав 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();
        }
    
    }
    
  2. использовать Runnable для огня и забыть звонки. Использовать Callable для проверки результата.

  3. Callable можно передать в invokeAll метод в отличие от Runnable. Методы invokeAny и invokeAll выполните наиболее часто используемые формы массового выполнения, выполнив набор задач, а затем дождавшись хотя бы одного или всех полный

  4. тривиальная разница: имя метода должно быть реализовано => run() на Runnable и call() на Callable.


Как уже упоминалось здесь, вызываемый является относительно новым интерфейсом, и он был введен как часть пакета параллелизма. Как вызываемые, так и запускаемые могут использоваться с исполнителями. Поток класса (который реализует сам Runnable) поддерживает только Runnable.

вы все еще можете использовать Runnable с исполнителями. Преимущество Callable в том, что вы можете отправить его исполнителю и сразу же получить будущий результат, который будет обновлен по завершении выполнения. То же самое может быть реализовано с помощью Runnable, но в этом случае вам придется управлять результатами самостоятельно. Например, можно создать очередь результатов, которая будет содержать все результаты. Другой поток может ждать в этой очереди и обрабатывать результаты, которые поступают.


+-------------------------------------+--------------------------------------------------------------------------------------------------+
|              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 в Java 1.5, чем изменение уже существующего Runnable интерфейс, который был частью Java с Java 1.0. источник


разница между вызываемым и Runnable следующие:

  1. вызываемый вводится в JDK 5.0, но Runnable вводится в JDK 1.0
  2. вызываемый имеет метод call (), но Runnable имеет метод run ().
  3. Callable имеет метод вызова, который возвращает значение, но Runnable имеет метод run, который не возвращает никакого значения.
  4. метод вызова может вызвать проверенное исключение, но метод run не может бросить проверенный исключение.
  5. вызываемый метод use submit() для размещения в очереди задач, но запускаемый метод execute () для размещения в очереди задач.

публичный интерфейс Runnable: Runnable интерфейс должен быть реализован любым классом, экземпляры которого должны выполняться потоком. Класс должен определить метод без аргументов, называемый run. Этот интерфейс предназначен для обеспечения общего протокола для объектов, которые хотят выполнять код, пока они активны. Например, Runnable реализуется потоком класса. Быть активным означает, что поток был запущен и еще не остановившийся.

кроме того, Runnable предоставляет средства для активного класса, а не подклассов потока. Класс, реализующий Runnable, может выполняться без подклассов Thread путем создания экземпляра Thread и передачи себя в качестве цели. В большинстве случаев интерфейс Runnable следует использовать, если планируется переопределить только метод run () и никакие другие методы потока. Это важно, потому что классы не должны быть подклассами, если программист не намерен изменение или усиление фундаментального поведения класса.

с: JDK1.0


открытый интерфейс вызываемый:

задача, которая возвращает результат и может бросить исключение. Реализаторы определяют один метод без аргументов Call. Вызываемый интерфейс аналогичен Runnable, поскольку оба предназначены для классов, экземпляры которых потенциально выполняются другим потоком. A Runnable, однако, не возвращает результат и не может выбросить проверенное исключение.

класс Executors содержит методы утилиты для преобразования из других распространенных форм в вызываемые классы.

с: С JDK 1.5