Далее на странице
Интерфейс 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. Некоторые темы мне довольно сложно освоить и усвоить. Поэтому я пишу такие вот статья с примерами. Делаю я это в большей степени для себя. Так мне проще понять и запомнить. Если кому-то пригодится – буду рад.
Этот материал используется исключительно в учебных целях и никакой коммерческой выгоды не несет. Текст частично взят из нейросети Яндекса, частично написан мною – материал берется из разных источников. Код писал сам, но за основу опять же брал какие-то уже существующие данные.
Если я где-то ошибся, что-то не правильно/не так описал – это нормально. Во-первых, я учусь, во-вторых, ни на что не претендую. Просьба это понимать.