Для чего используется callable call java

Callable и будущее в Java

Потребность в Callable

Существует два способа создания потоков — один путем расширения класса Thread, а другой — создания потока с Runnable. Однако в Runnable отсутствует одна особенность, заключающаяся в том, что мы не можем сделать поток, возвращающий результат, когда он завершается, т.е. когда run () завершается. Для поддержки этой функции в Java присутствует интерфейс Callable.

Callable против Runnable

Подпись метода, которая должна быть переопределена для реализации Callable.

Вот код для примера Callable, который вернет случайное число после задержки около 0 — 4 секунд.

// Java-программа для иллюстрации Callable
// вернуть случайное число

class CallableExample implements Callable

public Object call() throws Exception

// Создать генератор случайных чисел

Random generator = new Random();

Integer randomNumber = generator.nextInt( 5 );

// Для имитации тяжелых вычислений,

// мы задерживаем поток на некоторое случайное время

Будущее

Когда метод call () завершается, ответ должен быть сохранен в объекте, известном основному потоку, чтобы основной поток мог знать о результате, возвращенном потоком. Как программа сохранит и получит этот результат позже? Для этого можно использовать объект Future. Думайте о Будущем как о объекте, который содержит результат — он может не удерживать его прямо сейчас, но он будет делать это в будущем (как только Callable вернется). Таким образом, будущее — это в основном один из способов, которым основной поток может отслеживать прогресс и результат других потоков. Для реализации этого интерфейса необходимо переопределить 5 методов, но, как показано в примере ниже, используется конкретная реализация из библиотеки, здесь перечислены только важные методы.

Заметьте, что Callable и Future делают две разные вещи — Callable похож на Runnable в том, что он инкапсулирует задачу, предназначенную для выполнения в другом потоке, тогда как Future используется для хранения результата, полученного из другого потока. Фактически, Future может быть настроен на работу и с Runnable, и это станет ясно, когда исполнители появятся.

Для создания потока требуется Runnable. Для получения результата требуется будущее.

Библиотека Java имеет конкретный тип FutureTask, который реализует Runnable и Future, сочетая удобство обеих функций.
FutureTask можно создать, предоставив его конструктору Callable. Затем объект FutureTask предоставляется конструктору Thread для создания объекта Thread. Таким образом, косвенно поток создается с помощью Callable. Для дальнейшего акцентирования, обратите внимание, что нет способа создать поток напрямую с помощью Callable.

Вот код для полного примера с использованием Callable и FutureTask.

// Java-программа для иллюстрации Callable и FutureTask
// для генерации случайных чисел

Источник

Concurrent интерфейсы Callable, Future

Интерфейс Callable

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

С документацией интерфейса Callable можно познакомиться здесь.

Интерфейс Future

Интерфейс Future также, как и интерфейс Callable, использует Generic’и. Методы интерфейса можно использовать для проверки завершения работы потока, ожидания завершения и получения результата. Результат выполнения может быть получен методом get, если поток завершил работу. Прервать выполнения задачи можно методом cancel. Дополнительные методы позволяют определить завершение задачи : нормальное или прерванное. Если задача завершена, то прервать ее уже невозможно.

Методы интерфейса Future

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

С документацией интерфейса Future можно познакомиться здесь.

Пример использования интерфейсов Callable, Future

Рассмотрим простейший пример использования интерфейсов Callable и Future. Основная идея данного примера – показать, как можно, используя Future, узнать статус Callable потока и получить возвращенный объект. В примере используется объект executor типа ExecutorService, формирующий пул из трех потоков. Метод submit с параметром Callable возвращает объект Future для каждого из стартуемого потоков.

Класс CallableClass, реализующий интерфейс Callable, использует объект String в качестве generic’a. Соответственно и каждый объект Future также должен использовать тип объекта String.

Результат выполнения

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

Источник

Интерфейсы Callable и Future в Java

Интерфейс Java Callable(java.util.concurrent.Callable) представляет асинхронную задачу, которая может быть выполнена отдельным потоком. Например, можно передать объект Callable в Java ExecutorService, который затем выполнит его асинхронно. Метод call() вызывается для выполнения асинхронной задачи.

Интерфейс Callable довольно прост. Он содержит единственный метод с именем call().

Если задача выполняется асинхронно, результат обычно передается обратно через Java Future. Это тот случай, когда Callable передается в ExecutorService для одновременного выполнения.

Для чего используется callable call java. Смотреть фото Для чего используется callable call java. Смотреть картинку Для чего используется callable call java. Картинка про Для чего используется callable call java. Фото Для чего используется callable call java

Callable использует Generic для определения типа возвращаемого объекта. Класс Executors предоставляет полезные методы для выполнения Java Callable в пуле потоков. Поскольку вызываемые задачи выполняются параллельно, нам нужно дождаться возвращенного объекта.

Callable задачи возвращают объект java.util.concurrent.Future. Используя объект Java Future, мы можем узнать состояние задачи Callable и получить возвращенный объект. Он предоставляет метод get(), который может ожидать завершения Callable и затем возвращать результат.

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

Существуют методы isDone() и isCancelled() для определения текущего состояния связанной вызываемой задачи.

Вот простой пример задачи с Callable, которая возвращает имя потока, выполняющего задачу через одну секунду. Мы используем платформу Executor для параллельного выполнения 100 задач и используем Java Future для получения результата представленных задач.

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

Вот фрагмент вывода вышеуказанной программы.

Mon Dec 31 20:40:15 PST 2012::pool-1-thread-1
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-3
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-4
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-5
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-6
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-7
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-8
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-9
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-10
Mon Dec 31 20:40:16 PST 2012::pool-1-thread-2
.

Что делать, если мы хотим переопределить некоторые методы, например, переопределить метод get() для тайм-аута через некоторое время по умолчанию, а не ждать бесконечно?

В этом случае пригодится класс Java FutureTask, который является базовой реализацией Future.

Callable против Runnable

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

Callable отличается от Runnable тем, что метод run() не возвращает значение и не может генерировать исключения (только RuntimeExceptions).

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

Средняя оценка / 5. Количество голосов:

Или поделись статьей

Видим, что вы не нашли ответ на свой вопрос.

Источник

Многопоточное программирование в Java 8. Часть первая. Параллельное выполнение кода с помощью потоков

Для чего используется callable call java. Смотреть фото Для чего используется callable call java. Смотреть картинку Для чего используется callable call java. Картинка про Для чего используется callable call java. Фото Для чего используется callable call java

Добро пожаловать в первую часть руководства по параллельному программированию в Java 8. В этой части мы на простых примерах рассмотрим, как выполнять код параллельно с помощью потоков, задач и сервисов исполнителей.

Впервые Concurrency API был представлен вместе с выходом Java 5 и с тех пор постоянно развивался с каждой новой версией Java. Большую часть примеров можно реализовать на более старых версиях, однако в этой статье я собираюсь использовать лямбда-выражения. Если вы все еще не знакомы с нововведениями Java 8, рекомендую посмотреть мое руководство.

Потоки и задачи

Все современные операционные системы поддерживают параллельное выполнение кода с помощью процессов и потоков. Процесс — это экземпляр программы, который запускается независимо от остальных. Например, когда вы запускаете программу на Java, ОС создает новый процесс, который работает параллельно другим. Внутри процессов мы можем использовать потоки, тем самым выжав из процессора максимум возможностей.

Поскольку интерфейс Runnable функциональный, мы можем использовать лямбда-выражения, которые появились в Java 8. В примере мы создаем задачу, которая выводит имя текущего потока на консоль, и запускаем ее сначала в главном потоке, а затем — в отдельном.

Результат выполнения этого кода может выглядеть так:

Из-за параллельного выполнения мы не можем сказать, будет наш поток запущен до или после вывода «Done!» на экран. Эта особенность делает параллельное программирование сложной задачей в больших приложениях.

Потоки могут быть приостановлены на некоторое время. Это весьма полезно, если мы хотим сэмулировать долго выполняющуюся задачу. Например, так:

Работать с потоками напрямую неудобно и чревато ошибками. Поэтому в 2004 году в Java 5 добавили Concurrency API. Он находится в пакете java.util.concurrent и содержит большое количество полезных классов и методов для многопоточного программирования. С тех пор Concurrency API непрерывно развивался и развивается.

Давайте теперь подробнее рассмотрим одну из самых важных частей Concurrency API — сервис исполнителей (executor services).

Исполнители

Concurrency API вводит понятие сервиса-исполнителя (ExecutorService) — высокоуровневую замену работе с потоками напрямую. Исполнители выполняют задачи асинхронно и обычно используют пул потоков, так что нам не надо создавать их вручную. Все потоки из пула будут использованы повторно после выполнения задачи, а значит, мы можем создать в приложении столько задач, сколько хотим, используя один исполнитель.

Вот как будет выглядеть наш первый пример с использованием исполнителя:

Класс Executors предоставляет удобные методы-фабрики для создания различных сервисов исполнителей. В данном случае мы использовали исполнитель с одним потоком.

Вот как я предпочитаю останавливать исполнителей:

Исполнитель пытается завершить работу, ожидая завершения запущенных задач в течение определенного времени (5 секунд). По истечении этого времени он останавливается, прерывая все незавершенные задачи.

Callable и Future

Давайте напишем задачу, которая возвращает целое число после секундной паузы:

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

Задачи жестко связаны с сервисом исполнителей, и, если вы его остановите, попытка получить результат задачи выбросит исключение:

Таймауты

Любой вызов метода future.get() блокирует поток до тех пор, пока задача не будет завершена. В наихудшем случае выполнение задачи не завершится никогда, блокируя ваше приложение. Избежать этого можно, передав таймаут:

Выполнение этого кода вызовет TimeoutException :

Вы уже, возможно, догадались, почему было выброшено это исключение: мы указали максимальное время ожидания выполнения задачи в одну секунду, в то время как ее выполнение занимает две.

InvokeAll

InvokeAny

Используем этот метод, чтобы создать несколько задач с разными строками и задержками от одной до трех секунд. Отправка этих задач исполнителю через метод invokeAny() вернет результат задачи с наименьшей задержкой. В данном случае это «task2»:

ForkJoinPool впервые появился в Java 7, и мы рассмотрим его подробнее в следующих частях нашего руководства. А теперь давайте посмотрим на исполнители с планировщиком (scheduled executors).

Исполнители с планировщиком

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

ScheduledExecutorService способен запускать задачи один или несколько раз с заданным интервалом.

Этот пример показывает, как заставить исполнитель выполнить задачу через три секунды:

Кроме того, он принимает начальную задержку, которая определяет время до первого запуска.

Обратите внимание, что метод scheduleAtFixedRate() не берет в расчет время выполнения задачи. Так, если вы поставите задачу, которая выполняется две секунды, с интервалом в одну, пул потоков рано или поздно переполнится.

В этом примере мы ставим задачу с задержкой в одну секунду между окончанием выполнения задачи и началом следующей. Начальной задержки нет, и каждая задача выполняется две секунды. Так, задачи будут запускаться на 0, 3, 6, 9 и т. д. секунде. Как видите, метод scheduleWithFixedDelay() весьма полезен, если мы не можем заранее сказать, сколько будет выполняться задача.

Это была первая часть серии статей про многопоточное программирование. Настоятельно рекомендую разобрать вышеприведенные примеры самостоятельно. Все они доступны на GitHub. Можете смело форкать репозиторий и добавлять его в избранное.

Надеюсь, вам понравилась статья. Если у вас возникли какие-либо вопросы, вы можете задать их в твиттере.

Источник

Java Callable and Future Tutorial

Welcome to the fourth part of my tutorial series on Java Concurrency. In earlier tutorials, we learned the basics of concurrency, threads, runnables and executor services. In this tutorial, we’ll learn about Callable and Future.

In the previous tutorials, we used a Runnable object to define the tasks that are executed inside a thread. While defining tasks using Runnable is very convenient, it is limited by the fact that the tasks can not return a result.

What if you want to return a result from your tasks?

Well, Java provides a Callable interface to define tasks that return a result. A Callable is similar to Runnable except that it can return a result and throw a checked exception.

Executing Callable tasks using ExecutorService and obtaining the result using Future

The submit() method of executor service submits the task for execution by a thread. However, it doesn’t know when the result of the submitted task will be available. Therefore, it returns a special type of value called a Future which can be used to fetch the result of the task when it is available.

The concept of Future is similar to Promise in other languages like Javascript. It represents the result of a computation that will be completed at a later point of time in future.

ExecutorService.submit() method returns immediately and gives you a Future. Once you have obtained a future, you can execute other tasks in parallel while your submitted task is executing, and then use future.get() method to retrieve the result of the future.

Cancelling a Future

You can cancel a future using Future.cancel() method. It attempts to cancel the execution of the task and returns true if it is cancelled successfully, otherwise, it returns false.

You can use isCancelled() method to check if a task is cancelled or not. Also, after the cancellation of the task, isDone() will always true.

The future.get() method blocks and waits for the task to complete. If you call an API from a remote service in the callable task and the remote service is down, then future.get() will block forever, which will make the application unresponsive.

The future.get() method will throw a TimeoutException if the task is not completed within the specified time.

Submit multiple tasks and wait for all of them to complete.

You can execute multiple tasks by passing a collection of Callables to the invokeAll() method. The invokeAll() returns a list of Futures. Any call to future.get() will block until all the Futures are complete.

In the above program, the first call to future.get() statement blocks until all the futures are complete. i.e. the results will be printed after 5 seconds.

Submit multiple tasks and wait for any one of them to complete

The invokeAny() method accepts a collection of Callables and returns the result of the fastest Callable. Note that, it does not return a Future.

You can find the all the code snippets used in this tutorial in my github repository. I encourage you to fork the repo and practice the programs yourself.

Don’t forget to check out the next post in this tutorial series for learning about various issues related to concurrent programs and how to avoid them.

Thank you for reading. Please ask any questions in the comment section below.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *