Читаем Многопоточное программирование в Java полностью

То есть этот метод не создает никакого нового пула потоков, а отправляет нас к фреймворку fork/join.

Помимо классов RecursiveAction и RecursiveTask, Java 8 вводит класс CountedCompleter, который реализует класс ForkJoinTask.

Класс CountedCompleter обеспечивает механизм для выполнения метода после завершения всех подзадач.



Это метод onCompletion класса CountedCompleter.

Для вызова метода onCompletion, в той части метода compute, где идет вычисление подзадачи, достигшей минимального размера, мы вызываем метод tryComplete, который вызывает метод onCompletion.



Когда задача завершает метод onCompletion, вызывается метод tryComplete родительской подзадачи, и так далее до источника.

Если необходимо вернуть результат, переопределяется метод getRawResult класса CountedCompleter.

Каждый раз, когда объявляется новая подзадача, следует вызывать метод addToPendingCount.

Благодаря этому изменяется внутренний счетчик ожидающих задач.

Этот счетчик определяет, были ли выполнены задачи.

Если это не так, тогда счетчик уменьшается.

Когда задачи завершаются и счетчик обнуляется и вызывается метод tryComplete, событие завершения отправляется во все задачи CountedCompleter.

Если метод tryComplete не будет вызван перед возвратом, задача будет считаться незавершенной и будет выполняться неопределенно долго.

CompletableFuture


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



Java 8 представляет класс CompletableFuture, который позволяет выполнять задачи в потоке, отдельном от основного потока приложения, и уведомлять основной поток о прогрессе, завершении или сбое задачи.



Таким образом, ваш основной поток не блокируется/не ждет завершения задачи и может выполнять другие задачи параллельно.

CompletableFuture является реализацией интерфейса Future, который использовался нами как ссылка на результат асинхронного вычисления.

Он предоставлял метод isDone, чтобы проверить, выполнено ли вычисление или нет, и метод get для получения результата вычисления при его выполнении.

Однако интерфейс Future имеет некоторые недостатки.

При его использовании результат вычисления невозможно завершить вручную.

Например, вы написали функцию для получения данных из удаленного сервиса.

Так как этот вызов занимает много времени, вы запускаете его в отдельном потоке и возвращаете Future из своей функции.

Предположим теперь, что, если удаленный сервис недоступен, вы хотите завершить Future вручную с кэшированными данными.

Сделать это с помощью Future нельзя.

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

Future предоставляет метод get, который блокирует до тех пор, пока результат не будет доступен.

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

Далее, нельзя соединить вместе несколько объектов Future.

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

Вы не можете создать такой асинхронный рабочий поток с помощью Future.

Далее, вы не можете комбинировать несколько объектов Future вместе.

Например, у вас есть несколько различных Future, которые вы хотите запустить параллельно, а затем выполнить некоторую функцию после того, как все они завершатся.

Вы тоже не можете это сделать с помощью интерфейса Future.

Кроме того, интерфейс Future не имеет конструкции обработки исключений.

Все эти проблемы решает класс CompletedFuture, который реализует интерфейсы Future и CompletionStage и предоставляет набор методов для создания, соединения и объединения нескольких Future. Он также поддерживает обработку исключений.

Для выполнения задачи в отдельном потоке, мы применяем статический метод supplyAsync, который принимает реализацию интерфейса Supplier и выполняет эту реализацию в потоке пула потоков ForkJoinPool.



Интерфейс Supplier имеет единственный метод get, который необходимо определить.

Если вы хотите принудительно завершить вычисление, вы вызываете метод complete объекта CompletableFuture и возвращаете результат, который вы указали в качестве аргумента метода.

Если вы хотите выполнить задачу без возврата результата, вы вызываете метод runAsync и передаете ему объект Runnable.

Также вы можете выполнить задачу в каком-либо другом пуле потоков, явно указав Executor.



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

Для создания полностью асинхронного кода, мы должны иметь возможность подключить обратный вызов к CompletableFuture, который должен автоматически вызываться при завершении вычисления.

И мы сможем написать логику, которая должна быть выполнена после завершения Future внутри нашей функции обратного вызова.

Можно присоединить обратный вызов к CompletableFuture, используя методы thenApply, thenAccept и thenRun.

Перейти на страницу:

Похожие книги

«Ага!» и его секреты
«Ага!» и его секреты

Вы бы не хотели, скажем, изобрести что-то или открыть новый физический закон, а то и сочинить поэму или написать концерт для фортепьяно с оркестром?Не плохо бы, верно? Только как это сделать? Говорят, Шиллер уверял, будто сочинять стихи ему помогает запах гнилых яблок. И потому, принимаясь за работу, всегда клал их в ящик письменного стола. А физик Гельмгольц поступал иначе. Разложив все мысленно по полочкам, он дожидался вечера и медленно поднимался на гору лесной дорогой. Во время такой прогулки приходило нужное решение.Словом, сколько умов, столько способов заставить мозг работать творчески. А нет ли каких-то строго научных правил? Одинаковы ли они для математиков, биологов, инженеров, поэтов, художников? Да и существуют ли такие приемы, или каждый должен полагаться на свои природные способности и капризы вдохновения?Это тем более важно знать, что теперь появились «электронные ньютоны» — машины, специальность которых делать открытия. Но их еще нужно учить.Решающее слово здесь принадлежит биологам: именно они должны давать рецепты инженерам. А биологи и сами знают о том, как мы думаем, далеко не все. Им предстоит еще активнее исследовать лабораторию нашего мышления.О том, как ведутся эти исследования, как постепенно «умнеют» машины, как они учатся и как их учат, — словом, о новой науке эвристике рассказывает эта книга.

Елена Викторовна Сапарина

Зарубежная компьютерная, околокомпьютерная литература
Создание трилогии BioShock. От Восторга до Колумбии
Создание трилогии BioShock. От Восторга до Колумбии

Всего за три игры сага BioShock заняла особое место в сердцах игроков. Она может похвастаться проработанными и совершенно уникальными персонажами и мирами. Действие первых двух частей происходит в подводном городе Восторг, где игрок погружается в стиль ар-деко и атмосферу 1950-х годов. Третья часть, BioShock Infinite, переносит вас в 1912 год и приглашает исследовать небесный город Колумбия в сеттинге стимпанка.В книге вас ждут:[ul]рассуждение об источниках вдохновения создателя серии Кена Левина;исследование уникального геймплея и механик;подробности разработки игр франшизы от идеи до выпуска;глубокий анализ сюжета, тем и персонажей каждой части.[/ul]Авторы отдают дань уважения популярной серии игр, которая, несмотря на короткую историю, уже получила признание критиков.В формате PDF A4 сохранен издательский макет книги.

Мехди Эль Канафи , Николя Курсье , Рафаэль Люка

Зарубежная компьютерная, околокомпьютерная литература