Из-за необходимой задержки между вызовами, я бы предложил java.util.Timer
или java.util.concurrent.ScheduledThreadPoolExecutor
. Timer
очень просто и идеально подходит для этого варианта использования. Но если дополнительные требования к планированию будут определены позже, один Executor
может обработать все из них. В любом случае используйте метод с фиксированной задержкой, а не метод с фиксированной скоростью.
Повторяющаяся задача опрашивает параллельную очередь для объекта запроса. Если есть ожидающий запрос, задача выполняет его и возвращает результат посредством обратного вызова. Запрос на службу и обратный вызов для вызова являются членами объекта запроса.
Приложение хранит ссылку на общую очередь. Чтобы запланировать запрос, просто добавьте его в очередь.
Просто чтобы уточнить, если очередь пуста при выполнении запланированной задачи, запрос не выполняется. Простой подход состоит в том, чтобы просто завершить задачу, и планировщик вызовет задачу через секунду, чтобы проверить снова.
Однако это означает, что запуск задачи может занять до одной секунды, даже если в последнее время запросы не обрабатывались. Если эта ненужная задержка недопустима, вероятно, предпочтительнее написать собственный поток, чем использовать Timer
или ScheduledThreadPoolExecutor
. В вашем собственном цикле синхронизации у вас есть больший контроль над расписанием, если вы решите блокировать пустую очередь до тех пор, пока не будет доступен запрос. Встроенные таймеры не гарантированно ждут целую секунду после предыдущего выполнения Закончено ; они обычно планируются относительно времени начала задания.
Если вы имеете в виду этот второй случай, ваш метод run()
будет содержать цикл. Каждая итерация начинается с , блокируя в очереди до получения запроса, затем записывая время. После обработки запроса время проверяется снова. Если разница во времени составляет менее одной секунды, sleep для оставшейся части. Эта настройка предполагает, что между началом одного запроса и следующим требуется задержка в одну секунду. Если требуется задержка между окончанием одного запроса и следующим, вам не нужно проверять время; просто спать на секунду.
Еще одна вещь, на которую следует обратить внимание, это то, что служба может принимать несколько запросов в одном запросе, что уменьшит накладные расходы. Если это так, воспользуйтесь этим, заблокировав take()
для первого элемента, затем используя poll()
, возможно, с очень коротким временем блокировки (5 мс или около того), чтобы увидеть, если приложение делает больше запросов. Если это так, они могут быть объединены в один запрос к службе. Если queue
является BlockingQueue<? extends Request>
, это может выглядеть примерно так:
Collection<Request> bundle = new ArrayList<Request>();
bundle.add(queue.take());
while (bundle.size() < BUNDLE_MAX) {
Request req = queue.poll(EXTRA, TimeUnit.MILLISECONDS);
if (req == null)
break;
bundle.add(req);
}
/* Now make one service request with contents of "bundle". */