Подтвердить что ты не робот

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

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

4b9b3361

Ответ 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, однако, не возвращает результат и не может выдать проверенное исключение.

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

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

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

  4. Тривиальная разница: имя метода для реализации => 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 заключается в следующем:

  1. Callable представлен в JDK 5.0, а Runnable представлен в JDK 1.0
  2. У Callable есть метод call(), но у Runnable есть метод run().
  3. У Callable есть метод call, который возвращает значение, но у Runnable есть метод run, который не возвращает никакого значения.
  4. вызывающий метод может выдать проверенное исключение, но метод run не может выдать проверенное исключение.
  5. Вызываемое использование метода 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();
    }
}