Разница между Runnable и Callable в java

Java

Разница между Runnable и Callable в java

В многопоточной разработке java Runnable всегда был ядром многопоточности, а Callable — это расширенная версия, добавленная в java1.5.

В этой статье мы подробно обсудим разницу между Runnable и Callable.

Рабочий механизм

Сначала взгляните на определения интерфейса Runnable и Callable:

@FunctionalInterface
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();
}
@FunctionalInterface
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(), а Callable — метод call().

Все мы знаем, что есть два способа настроить Thread: один — наследовать Thread, но реализовать интерфейс Runnable, потому что Thread сам по себе является реализацией Runnable:

class Thread implements Runnable {
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
    ...

Таким образом, Runnable может выполняться через Runnable и ExecutorService, которые мы представили ранее, а Callable — только через ExecutorService.

Разница в возвращаемом значении

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

Если мы все отправим через ExecutorService, увидим разницу:

  • использовать работающий
    public void executeTask() {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future future = executorService.submit(()->log.info("in runnable!!!!"));
        executorService.shutdown();
    }
  • использовать вызываемый
    public void executeTask() {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future future = executorService.submit(()->{
            log.info("in callable!!!!");
            return "callable";
        });
        executorService.shutdown();
    }

Хотя мы оба возвращаем Future, Future не будет содержать никакого значения в случае запуска.

Обработка исключений

Определение метода run() в Runnable не генерирует никаких исключений, поэтому любое проверенное исключение необходимо обрабатывать в методе реализации run().

Метод Call() Callable генерирует исключение, поэтому вы можете поймать Checked Exception вне метода call(). Давайте посмотрим на обработку исключений в Callable.

 public void executeTaskWithException(){
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future future = executorService.submit(()->{
            log.info("in callable!!!!");
            throw new CustomerException("a customer Exception");
        });
        try {
            Object object= future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
            e.getCause();
        }
        executorService.shutdown();
    }

В приведенном выше примере мы выбрасываем пользовательское исключение CustomerException в Callable.

Это исключение будет включено в возвращаемое Future. Когда мы вызываем метод future.get(), будет выброшено ExecutionException.Через e.getCause() мы можем получить конкретную информацию об исключении, содержащуюся в нем.

Примеры этой статьи могут относиться кGitHub.com/Dadean2009/приходите…

Дополнительные руководства см.блог флайдина