Скажем, у меня есть очередь, полная задач, которые мне нужно отправить в службу исполнителя. Я хочу, чтобы они обрабатывались по одному. Самый простой способ, который я могу придумать, это:
- Взять задание из очереди
- Отправить его исполнителю
- Позвоните .get на возвращенное будущее и заблокируйте, пока результат не будет доступен
- Возьми еще одно задание из очереди ...
Тем не менее, я пытаюсь избежать блокировки полностью. Если у меня будет 10 000 таких очередей, для которых нужно обрабатывать свои задачи по одной, я исчерпаю пространство стека, потому что большинство из них будут удерживать заблокированные потоки.
То, что я хотел бы, это представить задачу и предоставить обратный вызов, который вызывается, когда задача завершена. Я буду использовать это уведомление об обратном вызове в качестве флага для отправки следующего задания. (Functional Java и Jetlang, очевидно, используют такие неблокирующие алгоритмы, но я не могу понять их код)
Как я могу сделать это, используя java.util.concurrent JDK, если не считать написания моей собственной службы исполнителя?
(очередь, которая кормит меня этими задачами, может сама блокироваться, но это проблема, которая будет решена позже)
Callback
интерфейс, который вы объявляете; не из библиотеки. В настоящее время я, вероятно, просто используюRunnable
,Consumer
илиBiConsumer
, в зависимости от того, что мне нужно, чтобы передать задание слушателю.В Java 8 вы можете использовать CompletableFuture . Вот пример, который я имел в своем коде, где я использую его для извлечения пользователей из моего пользовательского сервиса, сопоставления их с моими объектами представления, а затем обновления моего представления или отображения диалога об ошибках (это приложение с графическим интерфейсом):
Это выполняется асинхронно. Я использую два частных метода:
mapUsersToUserViews
иupdateView
.источник
Используйте готовый API-интерфейс Guava и добавьте обратный вызов. Ср с веб-сайта :
источник
Вы можете расширить
FutureTask
класс и переопределитьdone()
метод, а затем добавитьFutureTask
объект вExecutorService
, так чтоdone()
метод будет вызван, когдаFutureTask
завершится немедленно.источник
then add the FutureTask object to the ExecutorService
не могли бы вы сказать мне, как это сделать?ThreadPoolExecutor
также имеетbeforeExecute
иafterExecute
подключает методы, которые вы можете переопределить и использовать. Вот описание отThreadPoolExecutor
«S Javadocs .источник
Использовать
CountDownLatch
.Это из
java.util.concurrent
и это точно способ дождаться завершения нескольких потоков, прежде чем продолжить.Чтобы добиться эффекта обратного вызова, за которым вы ухаживаете, это требует немного дополнительной дополнительной работы. А именно, обрабатывая это самостоятельно в отдельном потоке, который использует
CountDownLatch
и ожидает его, затем продолжает уведомлять обо всем, что вам нужно уведомить. Нет встроенной поддержки для обратного вызова или чего-либо подобного этому эффекту.РЕДАКТИРОВАТЬ: теперь, когда я понимаю ваш вопрос, я думаю, что вы зашли слишком далеко, без необходимости. Если вы берете регулярный
SingleThreadExecutor
, дайте ему все задачи, и он будет делать очереди изначально.источник
Если вы хотите убедиться, что никакие задачи не будут выполняться одновременно, используйте SingleThreadedExecutor . Задачи будут обрабатываться в порядке их отправки. Вам даже не нужно держать задачи, просто отправьте их в exec.
источник
Простой код для реализации
Callback
механизма с использованиемExecutorService
вывод:
Ключевые примечания:
newFixedThreadPool(5)
наnewFixedThreadPool(1)
Если вы хотите обработать следующую задачу после анализа результата
callback
предыдущей задачи, просто снимите комментарий ниже строкиВы можете заменить
newFixedThreadPool()
один изв зависимости от вашего варианта использования.
Если вы хотите обрабатывать метод обратного вызова асинхронно
а. Передать общую
ExecutorService or ThreadPoolExecutor
задачу Callableб. Преобразуйте ваш
Callable
метод вCallable/Runnable
задачус. Задача обратного вызова
ExecutorService or ThreadPoolExecutor
источник
Просто чтобы добавить ответ Мэтта, который помог, вот более конкретный пример, демонстрирующий использование обратного вызова.
Выход:
источник
Вы можете использовать реализацию Callable так, чтобы
где CallbackInterface является чем-то очень простым, как
и теперь основной класс будет выглядеть так
источник
Это расширение ответа Пача с использованием Guava
ListenableFuture
.В частности,
Futures.transform()
возвратыListenableFuture
могут быть использованы для цепочки асинхронных вызовов.Futures.addCallback()
возвращаетvoid
, поэтому не может использоваться для цепочки, но хорошо для обработки успеха / неудачи при асинхронном завершении.ПРИМЕЧАНИЕ. Помимо цепочки асинхронных задач,
Futures.transform()
вы также можете планировать каждую задачу для отдельного исполнителя (в этом примере не показано).источник