Совет по проблеме асинхронного программирования в Java - PullRequest
0 голосов
/ 07 августа 2020

У меня есть набор классов, которые инкапсулируют единицу работы в Google Таблицах. После вызова метода execute класса они передают запрос в службу вместе с обратным вызовом, который служба должна вызывать по завершении задачи. (Поскольку задачи не являются критическими и часто повторяются, служба просто регистрирует ошибки и не вызывает класс, если его запрос не выполняется).

В разрезе задачи выглядят следующим образом:

public void execute() {
  //preparatory stuff, then...
  Request r = new Request(this::callback);
  service.execute(r);
}

public void callback(Result result) {
  ...
}

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

Моя проблема в том, что я хотел бы запускать задачи асинхронно из клиентского кода, а затем выполнять произвольный обработчик после того, как они будут выполнены. Один из способов сделать это - дать классу обратный вызов в методе execute (), который он будет вызывать после завершения выполнения. Но я бы предпочел сделать это встроенным в код, такого рода вещи:

CompletableFuture.supplyAsync(() -> (new Task()).execute()).whenComplete((result, error) -> {});

Проблема в том, что завершение метода execute () не сигнализирует об окончании задача, поскольку задача все еще ожидает обратного вызова. Другое дело, что обратный вызов может никогда не поступить. Я не могу понять, как я должен go вызывать задачу, чтобы я мог запускать ее асинхронно и встроенно, как в приведенном выше коде, и когда класс Task явно решит, что она завершена, будет вызываться whenComplete (). Мне также понадобится тайм-аут, так как обратный вызов задач не может быть вызван.

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

Ответы [ 2 ]

0 голосов
/ 07 августа 2020

Собираюсь ответить на свой вопрос здесь: я просто изменил методы выполнения задачи, чтобы возвращать CompletableFuture<TaskResult> с TaskResult, содержащим желаемую информацию. Задача хранит CompletableFuture внутри и вызывает complete() по мере необходимости в последующих обратных вызовах. Не знаю, почему мне не удалось увидеть это решение.

0 голосов
/ 07 августа 2020

Я бы потратил некоторое время на поиски java .util.concurrent. Разве вы не можете просто использовать ExecutorService для многих из них? Вы можете submit () Callable code и вернуть будущее, вы можете отправить список Callables и задать тайм-аут, вы можете вызвать shutdown (), а затем awaitTermination (), чтобы дождаться остановки обработки. Вы можете получить эти обратные вызовы уведомлений, просто отправив Callable, который создает с интерфейсом обратного вызова и вызывает его, когда кажется, что это сделано.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...