«Единственный способ творить великие дела – это любить то, что ты делаешь»
Веб Ученик


Интерфейс Callable в Java предназначен для одноразовых задач, которые возвращают один результат. Он был введён в Java 5 и представляет собой более универсальный инструмент для работы с потоками. 

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

Java-код. Интерфейс Callable

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

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



Интерфейс Callable. Метод call() возвращает результат

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

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

Метод call() этого интерфейса возвращает результат и может бросить проверяемое исключение.

Java-код. Пример №1

public class Callable1 {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService threadPool = Executors.newFixedThreadPool(4);   // ПУЛ ПОТОКОВ

        MyCall myCall = new MyCall();       // Объект Callable
        threadPool.submit(myCall);          // Отправляем задачу myCall на выполнение в пул потоков

        threadPool.shutdown();
    }
}

// Класс MyCall реализует интерфейс Callable
class MyCall implements Callable {                      // Задача
    @Override
    public Integer call() throws Exception {            // Метод call() возвращает результат
        System.out.println("Интерфейс Callable");
        int a = 0;
        for (int i = 0; i < 5; i++) {
            a++;
        }
        return a;
    }
}																			// L 13

Результат в консоли

Интерфейс Callable

В примере №1 была описана задача с использованием интерфейса Callable. И отправлена на выполнение в пул потоков при помощи метода submit(). В результате мы увидели строку, которую выводит в консоль метод call(), но не увидели результат, который он возвращает.

Метод submit() - задача в очереди на выполнение

Метод submit() в Java ставит задачу в очередь на выполнение. В качестве входного параметра он принимает объект типа Callable или Runnable.

Это не простой метод. Следует разобраться, как он работает.

Метод submit() возвращает параметризованный объект типа Future. Этот объект можно использовать для доступа к результату выполнения задачи. С его помощью можно определить завершение выполнения задачи (метод isDone()) и получить доступ к результату (метод get) или исключительной ситуации, если в процессе выполнения задачи произошла ошибка.

Метод submit() используется, когда требуется контролировать результат выполнения задачи. Он помогает получать результаты работы или отменять задачу. Как результат выполнения задачи?

Future в Java - получить результат задачи. Метод get()

Результат выполнения задачи Callable можно получить с помощью объекта Future.

Поскольку метод submit() не ждёт завершения задачи, исполнитель не может вернуть результат напрямую. Вместо этого он возвращает специальный объект Future, у которого можно запросить результат задачи.

Future в Java — это интерфейс, который представляет результат асинхронного вычисления. С его помощью можно проверить, завершено ли выполнение задачи, дождаться её завершения и получить результат

Некоторые методы интерфейса Future:

  • cancel() — попытка завершить задачу.
  • get() — ожидание (при необходимости) завершения задачи, после чего можно будет получить результат.
  • get(long timeout, TimeUnit unit) — ожидание (при необходимости) завершения задачи в течение определённого времени, после чего можно будет получить результат.
  • isCancelled() — вернёт true, если выполнение задачи будет прервано прежде завершения.
  • isDone() — вернёт true, если задача завершена.

Пример использования: метод submit() сервиса ExecutorService отправляет задачу на выполнение потоком, но не знает, когда будет доступен результат. Поэтому он возвращает специальный объект Future, у которого можно запросить результат задачи, когда он станет доступен.

Для этого используется метод get(), который ждёт завершения Callable, чтобы вернуть результат. Если задача выполнена, он возвращает результат немедленно, в противном случае ожидает завершения задачи, а затем возвращает результат.

Метод get() является самым важным методом Future, который блокирует текущий поток до тех пор, пока задача не будет выполнена и результат не будет доступен. Если задача уже выполнена, get() сразу же возвращает результат. После завершения задачи он возвращает результат или выбрасывает исключение.

Java-код. Пример №2

public class Callable1 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {

        ExecutorService threadPool = Executors.newFixedThreadPool(4);   // ПУЛ ПОТОКОВ

        MyCall myCall = new MyCall();          // Объект Callable
        // threadPool.submit(myCall);          // 1. Отправляем задачу myCall на выполнение в пул потоков

        Future future = threadPool.submit(myCall);     // 2. Результат получаем в future
        Integer result = future.get();                          // 3. get() - возвращает результат
        System.out.println("Результат: " + result);

        threadPool.shutdown();
    }
}

// Класс MyCall реализует интерфейс Callable
class MyCall implements Callable {                      // Задача
    @Override
    public Integer call() throws Exception {            // Метод call() - выполнить и вернуть результат
        System.out.println("Интерфейс Callable");
        int a = 0;
        for (int i = 0; i < 5; i++) {
            a++;
        }
        return a;
    }
}																				// L 13

Результат в консоли

Интерфейс Callable
Результат: 5

Метод isDone - завершена ли задача?

Метод isDone(). Прежде чем вызывать метод get() мы можем проверить - завершена ли задача?

Метод isDone() в интерфейсе Future возвращает true, если задание (вычисления) завершено.

Завершёнными считаются задания, которые завершились штатным способом, завершились исключением или были отменены.

future.isDone();	// Завершена ли задача

Методы shutdown() и shutdownNow()

Метод shutdown() в интерфейсе ExecutorService инициирует плавную остановку. После его вызова ExecutorService больше не принимает новые задания. Все задания, которые раннее были переданы в ExecutorService, продолжат своё выполнение. 

Метод shutdownNow() пытается остановить текущие активные задания. Задачи, которые ждали своей очереди, отбрасываются и возвращаются в виде списка Runnable. Этот метод не ждёт завершения активно выполняемых задач, а пытается остановить их принудительно.

P.S.

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

Этот материал используется исключительно в учебных целях и никакой коммерческой выгоды не несет. Текст частично взят из нейросети Яндекса, частично написан мною – материал берется из разных источников. Код писал сам, но за основу опять же брал какие-то уже существующие данные.

Если я где-то ошибся, что-то не правильно/не так описал – это нормально. Во-первых, я учусь, во-вторых, ни на что не претендую. Просьба это понимать.

Потоки в Java
Интерфейс Callable Интерфейс Callable. Метод call() возвращает результатМетод submit() - задача в очереди на выполнениеFuture в Java - получить результат задачи. Метод get()Метод isDone - завершена ли задача?Методы shutdown() и shutdownNow()
Способы создания потоков 1 способ. Наследование от класса Thread2 способ. Реализация интерфейса RunnableСоздание объекта Runnable с использованием анонимного классаОпределяем поведение потока с помощью лямбда-выраженияСоздание и запуск потока с использованием лямбда-выражения
Ключевое слово Synchronized СинхронизацияСинхронизация методаСинхронизация блока кодаМьютекс и МониторСемафорСинхронизация в статических методах. Синхронизация по классуДополнительно. Объект МОНИТОРМожет ли поток блокировать мьютекс двух объектов?
Executor и ExecutorService Интерфейс ExecutorServiceExecutorService - реализация пула ПотоковСоздание пула потоков - Класс ExecutorsМетод execute() - выполнение задач в пуле потоковСоздание объекта Runnable с использованием анонимного класса
Проблемы многопоточности Первый способ - блокирующая синхронизацияВторой способ: lock free или неблокирующая синхронизацияLock-free программирование. Пакет java.util.concurrent.atomicCompare-and-Set в Java. AtomicТретий способ Wait-free
Пакет java.util.concurrent Атомики в Java. Lock-free и thread-safe. Compare-and-Swap (CAS)Интерфейсы Future и CallableФреймворк ExecutorКласс ExecutorsОчереди в java.util.concurrentПродюсер и консьюмер в JavaКоллекции для работы в многопоточной средеThreadLocal и ThreadLocalRandomСинхронизаторы - синхронизация потоков
Тематические публикации
site.komp36.ru Как начать свое дело? Свой сайт «Укладка плитки» 9 000 руб. Лендинг адаптируется под любой вид отделочных работ, продажу товаров или услуг. Сайт поможет найти новых клиентов
site.komp36.ru Продающий лендинг «Установка и продажа окон» 9 000 руб. Одностраничный продающий сайт. Установка и продажа окон, установка дверей, перегородок. Заявки прямо с сайта
Последние статьи
Популярные статьи
Тематические публикации
site.komp36.ru Как начать свое дело? Свой сайт «Укладка плитки» 9 000 руб. Лендинг адаптируется под любой вид отделочных работ, продажу товаров или услуг. Сайт поможет найти новых клиентов
site.komp36.ru Продающий лендинг «Установка и продажа окон» 9 000 руб. Одностраничный продающий сайт. Установка и продажа окон, установка дверей, перегородок. Заявки прямо с сайта