Разница между интерфейсами Runnable и Callable в Java - PullRequest
449 голосов
/ 26 сентября 2008

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

Ответы [ 12 ]

2 голосов
/ 23 октября 2018

Callable и Runnable оба похожи друг на друга и могут использоваться при реализации потока. В случае реализации Runnable необходимо реализовать метод run () , но в случае вызова необходимо реализовать метод call () , оба метода работают аналогично способы, но вызываемые call () , имеют большую гибкость. Между ними есть некоторые различия.

Разница между Работоспособным и вызываемым , как показано ниже -

1) run () метод runnable возвращает void , означает, что если вы хотите, чтобы ваш поток возвращал что-то, что вы можете использовать дальше, чем у вас есть нет выбора с помощью Runnable run () метод. Существует решение 'Callable' . Если вы хотите вернуть какую-либо вещь в виде объекта , то вам следует использовать Callable вместо Runnable . Вызываемый интерфейс имеет метод 'call ()', который возвращает Object .

Метод подписи - Runnable->

public void run(){}

Callable->

public Object call(){}

2) В случае метода Runnable run () , если возникает какое-либо проверенное исключение, необходимо обработать его с помощью блока try catch , но в случае Вызываемый вызов () метод, который вы можете выдать проверенное исключение , как показано ниже

 public Object call() throws Exception {}

3) Runnable поставляется с устаревшей Java 1.0 версией, но вызываемый поставляется с Java 1.5 версия с Executer рамки.

Если вы знакомы с Executers , тогда вам следует использовать Callable вместо Runnable .

Надеюсь, вы понимаете.

0 голосов
/ 03 июня 2019

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();
    }
}
...