что такое futuretask java
Описание и пример FutureTask
Одной из «неприятных» задач многопоточного приложения является определение состояния потока (работает или нет, реагирует на внешние воздействия или нет) и останов потока. Если рассматривать обычный поток Thread, то с ним могут возникнуть такие проблемы. Ведь в Java (JDK 1.5 и выше) нет механизма останова потока. Как известно метод Thread.stop() объявлен как Deprecated поскольку «не потокобезопасен», а безопасная инструкция Thread.interrupt() только сообщает потоку о необходимости остановки. Но если данное сообщение проигнорировано, т.е. разработчик не вставил обработку, то и поток не остановится.
И вот здесь на помощь разработчику приходит пакет Concurrent со своими интерфейсами java.util.concurrent.Callable, java.util.concurrent.Future. Данные интерфейсы (подробно представленные на сайте здесь ), а также их различные реализации позволяют решать задачи «внешнего» управления потоками, т.е. не в методе выполнения потока run() или call(). В данной статье будет рассмотрен класс FutureTask и приведен пример контроля состояния потоков и останова одного потока из другого.
Класс FutureTask
Класс-оболочка FutureTask базируется на конкретной реализации интерфейса Future. Чтобы создать реализацию данного класса необходим объект Callable; после этого можно использовать Java Thread Pool Executor для асинхронной обработки. Таким образом, FutureTask представляет удобный механизм для превращения Callable одновременно в Future и Runnable, реализуя оба интерфейса. Объект класса FutureTask может быть передан на выполнение классу, реализующему интерфейс Executor, либо запущен в отдельном потоке, как класс, реализующий интерфейс Runnable.
Конструкторы класса FutureTask
Класс FutureTask содержит следующие два конструктора :
Методы класса FutureTask
Метод | Описание |
---|---|
V get() | получение результата выполнения потока; вызов метода блокирует дальнейшее выполнения до окончания вычислений |
V get(long timeout, TimeUnit unit) | получение результата до окончания вычислений или до истечения указанного интервала времени; если в течение указанного времени вычисления не завершились, то вызывается исключение TimeoutException |
boolean cancel(boolean mayInterrupt) | отмена выполнения задачи; если задача уже стартована и параметр mayInterrupt равен true, то она прерывается, в противном случае, если вычисления еще не начаты, то они и не начнутся. При успешной отмене выполнения задачи метод возвращает значение true |
boolean isCancelled() | метод возвращает true, если задача была отменена до ее нормального завершения |
boolean isDone() | метод возвращает true, если выполнение задачи завершено, прервано или если в процессе ее выполнения возникло исключение |
Пример использования FutureTask
Рассмотрим простой пример использования FutureTask, в котором создается пул из 3-х потоков, реализующих интерфейс Callable в виде класса CallableDelay. Основная идея примера связана с проверками выполняемых потоков и отмены выполнения задачи одного из потоков.
Конструктор класса CallableDelay в качестве параметров получает временно́й размер задержки delay и идентификатор потока. В зависимости от значения идентификатора потока в методе call() выполняется соответствующее количество циклов с заданной задержкой, после чего поток завершает работу. Второй поток на первом цикле прерывает выполнение 3-го потока вызовом метода cancel. Метод call потока возвращает текстовый объект String в виде наименования потока.
Метод areTasksDone() проверяет завершение выполнения всех задач/потоков вызовом методов isDone() объектов futureTask. Если выполнение всех потоков завершены, то сервис executor останавливает свою работу методом shutdown().
В конструкторе примера создаются два массива из объектов типа CallableDelay и FutureTask. После этого формируется пул для трех потоков сервиса типа ExecutorService и потоки стартуют методом execute сервиса executor. В цикле выполняются различного рода проверки : завершения работы потока методом isDone(), ожидания завершения потока методом get() с временны́ми параметрами и отмены выполнения потока методом isCancelled().
Результат работы примера
При выполнении задачи информационные сообщения, представленные ниже, выводятся в консоль. Согласно последовательности вывода сообщений можно сказать, что при вызове метода isDone() объекта FutureTask 1-го потока программа перешла в режим ожидания завершения работы потока.
После завершения выполнения 1-го потока программа перешла к проверке 2-го потока методом get() с временно́й задержкой.Так как за предоставленное время поток не смог завершить работу, то был вызван TimeoutException и цикл проверки повторился снова.
Только после завершения работы 2-го потока программа перешла к проверке отмены/завершения 3-го потока. Метод isCancelled() подтвердил, что выполнение потока было прервано. Только после этого метод areTasksDone() подтвердил, что все потоки завершили выполнение и цикл проверок был прерван, сервис executor завершил выполнение методом shutdown().
Именование потоков
Стандартная схема именования потока соответствует формату pool-N-thread-M, где N обозначает последовательный номер пула, а M – порядковый номер потока в пуле. Так наименование pool-1-thread-2 означает второй поток в первом пуле жизненного цикла JVM. Каждый раз, когда создается новый пул, глобальный счетчик N инкрементится.
Будущее и FutureTask в Java
Будущее:
Future и FutureTask доступны в пакете java.util.concurrent из Java 1.5.
FutureTask:
Примеры: Создать две задачи. После того, как одно полностью выполнено, затем после ожидания 2000 миллисекунд выполняется второе задание
Примечание: онлайн IDE не работает должным образом с методом sleep ().
// Java-программа выполняет два FutureTask
// используя Runnable Interface
class MyRunnable implements Runnable <
private final long waitTime;
public MyRunnable( int timeInMillis)
// сон для пользователя в течение миллисекунды
// перед повторной проверкой
// вернуть имя текущего потока
catch (InterruptedException ex) <
// Класс FutureTaskExample оправдывает две будущие задачи
public static void main(String[] args)
// создаем два объекта класса MyRunnable
// для FutureTask и sleep 1000, 2000
// миллисекунда перед повторной проверкой
MyRunnable myrunnableobject1 = new MyRunnable( 1000 );
MyRunnable myrunnableobject2 = new MyRunnable( 2000 );
futureTask1 = new FutureTask<>(myrunnableobject1,
«FutureTask1 is complete» );
futureTask2 = new FutureTask<>(myrunnableobject2,
«FutureTask2 is complete» );
// создаем пул потоков 2 размера для ExecutorService
ExecutorService executor = Executors.newFixedThreadPool( 2 );
// отправляем futureTask1 в ExecutorService
// отправляем futureTask2 в ExecutorService
// если обе будущие задачи выполнены
if (futureTask1.isDone() && futureTask2.isDone()) <
System.out.println( «Both FutureTask Complete» );
// закрываем службу исполнителя
// ждать бесконечно долго
// задача для завершения
System.out.println( «FutureTask1 output = «
System.out.println( «Waiting for FutureTask2 to complete» );
// Подождите, если необходимо, чтобы вычисление завершилось,
Интерфейсы Callable и Future в Java
Интерфейс Java Callable(java.util.concurrent.Callable) представляет асинхронную задачу, которая может быть выполнена отдельным потоком. Например, можно передать объект Callable в Java ExecutorService, который затем выполнит его асинхронно. Метод call() вызывается для выполнения асинхронной задачи.
Интерфейс Callable довольно прост. Он содержит единственный метод с именем call().
Если задача выполняется асинхронно, результат обычно передается обратно через Java Future. Это тот случай, когда Callable передается в ExecutorService для одновременного выполнения.
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. Количество голосов:
Или поделись статьей
Видим, что вы не нашли ответ на свой вопрос.
Русские Блоги
Введение и использование FutureTask
Future
Простая демонстрация:
Принцип реализации FutureTask
Ниже мы представляем некоторые механизмы реализации внутри FutureTask. Следующее описывает из следующих пунктов:
1. Структура наследования классов
2. Основные переменные-члены
3. Переход внутреннего состояния
4. Анализ основного метода
Структура наследования 1 класса
Сначала посмотрим на структуру наследования FutureTask:
FutureTask реализует интерфейс RunnableFuture, а RunnableFuture наследует Runnable и Future, что означает, что FutureTask является одновременно Runnable и Future.
2 основные переменные-члены
Следующие переменные определены внутри FutureTask, и их значения следующие
3 Внутренний переход состояния
В FutureTask состояние используется для представления состояния задачи, а атомарность изменения значения состояния гарантируется операциями CAS.
После того, как задача отправлена и отменена до ее завершения, она может стать ОТМЕНЕННОЙ или ПРЕРЫВАННОЙ. При вызове метода cancel, если передается false, чтобы указать, что поток не будет прерван, состояние будет установлено на CANCELED, в противном случае состояние будет сначала изменено на INTERRUPTING, а затем на INTERRUPTED.
4 основных метода анализа
Далее давайте посмотрим на исходный код FutureTask. Давайте сначала посмотрим, как выполняется поток задачи. Когда задача отправляется в пул потоков, будет выполнен метод run () futureTask.
1 public void run()
Перевод, этот метод прошел следующие этапы
Комментарии в коде написаны очень четко, поэтому они не будут переведены. Атомарность изменений состояния гарантируется операцией CAS, предоставляемой небезопасным объектом. Переменная результата FutureTask сохраняет результат выполнения или объект исключения, который будет возвращен основным потоком.
2 get () и get (длинный таймаут, единица TimeUnit)
Задачи выполняются потоками, предоставленными пулом потоков, затем основной поток блокируется, пока поток задачи не разбудит их. Посмотрим, как это сделать, с помощью метода get (long timeout, TimeUnit unit)
Исходный код get очень краток. Во-первых, он проверяет параметры, а затем определяет, истек ли тайм-аут в соответствии с состоянием состояния. Если время истекло, это будет ненормально. Если нет, он вызовет отчет (ы) для получения окончательного результата.
Когда s COMPLETING указывает, что задача была отменена или была выполнена, вы можете вернуться напрямую.
5. Если задача все еще выполняется, инициализируйте WaitNode для текущего потока и войдите в очередь ожидания. Это похоже на очередь ожидания AQS, за исключением того, что 6, Node только связывает потоки и не имеет состояния. Ожидающие узлы в AQS отслеживают состояние.
7. Вычислите нано и определите, не истек ли время ожидания. Если время ожидания истекло, удалите все ожидающие узлы и сразу вернитесь в состояние. Если время истекает, значение состояния все еще ЗАВЕРШЕНО.
8. Если время ожидания не истекло, приостановите текущий поток в течение указанного времени с помощью метода, предоставленного классом LockSupprot, и дождитесь, пока поток задачи проснется или проснется с течением времени.
Когда поток приостановлен, если поток задачи завершает выполнение, ожидающий поток будет пробужден. Этот шаг выполняется в finishCompletion, и этот метод упоминался ранее. Давайте посмотрим, что именно делает этот метод
Как видно из кода и комментариев, функция этого метода в основном состоит в том, чтобы разбудить ожидающий поток. Как видно из вышеизложенного, когда задача завершается нормально или ненормально, вызывается finishCompletion, чтобы разбудить ожидающий поток. В это время ожидающий поток может проснуться и успешно получить результат. Взаимодействие с другими людьми
Наконец, давайте посмотрим на отмену задачи.
3 public boolean cancel(boolean mayInterruptIfRunning)
Обратите внимание, что операция отмены может не работать. Здесь мы сначала публикуем демонстрацию.
После многих тестов мы обнаружили, что существует два типа результатов печати, как показано на рисунке.
Результат первый
Результат второй
Во-первых, задача не отменяется вообще, а во-вторых, задача не отправлена успешно. Взаимодействие с другими людьми
Комментарий сигнатуры метода сообщает нам, что операция отмены может завершиться неудачно. Если текущая задача завершилась или была отменена, текущая операция отмены завершится ошибкой. Если задача еще не запущена, то она не будет выполнена. Это объясняет появление результата 2 на рисунке выше. Мы все еще анализируем, что делает cancel () из исходного кода.
Логика выполнения следующая
1. Если состояние не НОВОЕ, задача вот-вот войдет в конечное состояние, а прямой возврат false указывает, что операция отмены не удалась.
2. Состояние НОВОЕ, и задача могла быть выполнена или еще не запущена.
3. mayInterruptIfRunning указывает, следует ли прерывать поток. Если это так, попробуйте установить состояние ПРЕРЫВАНИЕ, прервать поток, а затем установить состояние в конечное состояние ПРЕРЫВАНИЕ.
4. Если mayInterruptIfRunning = false, поток не будет прерван и будет установлено состояние CANCELED.
5. Удалите ожидающий поток и просыпайтесь.
6. Вернуть истину.
Русские Блоги
[ Java] Разница и связь между Future и FutureTask
Связанное чтение
Краткое введение в будущую модель
Так называемый асинхронный вызов на самом деле является методом, который позволяет продолжить операцию, не дожидаясь возвращаемого значения вызываемой функции. На языке Java, попросту говоря, запускается другой поток для завершения части вычисления в вызове, так что вызов может продолжать выполняться или возвращаться без ожидания результата вычисления. Но вызывающей стороне все же нужно принять результат вычисления потока.
JDK5 добавил интерфейс Future для описания результата асинхронного вычисления. Хотя будущие и связанные с ними методы использования предоставляют возможность выполнять задачи асинхронно, получать результаты очень неудобно, а результаты задач можно получить только путем блокировки или опроса. Очевидно, что метод блокировки противоречит нашему первоначальному намерению асинхронного программирования: метод опроса потребляет ненужные ресурсы ЦП, и результаты вычислений не могут быть получены вовремя.
Future
В будущем необходимо отменить результат выполнения определенной задачи Runnable или Callable, проверить, завершен ли запрос, и получить результаты. При необходимости результат выполнения можно получить с помощью метода get, который будет блокироваться до тех пор, пока задача не вернет результат.
Класс Future находится в пакете java.util.concurrent. Это интерфейс:
Как видно из комментариев приведенного выше метода, Futrue предоставляет три функции:
1) определить, завершена ли задача;
2) Возможность прерывать задачи;
3) Возможность получить результаты выполнения задачи. (Чаще всего используется)
FutureTask
Можно видеть, что FutureTask может выполняться потоком как Runnable, а также как Future для получения возвращаемого значения Callable.
FutureTask предоставляет 2 конструктора:
Дать каштан
Используйте Futrue напрямую, чтобы получить возвращаемое значение: (в сочетании с вызываемым)
Очевидно, мы можем обнаружить, что время mid очень короткое, и основной поток сразу же запускается вниз, но время окончания длиннее, поэтому результат get () принадлежит методу блокировки.
FutureTask получить результаты: (используется в сочетании с Callbale)
Второй способ (просто простая упаковка):
Если вы используете Future для отмены без предоставления полезного результата, вы можете объявить формальный тип Future И вернуть null в качестве результата основной задачи.
Разница между Callable и Futrue: Callable используется для получения результатов, Future используется для получения результатов