Как я могу синхронизировать выполнение jBatch?
Я пишу программу jBatch с помощью jBeret. Я сейчас так делаю.
final JobOperator operator = BatchRuntime.getJobOperator();
logger.debug("operator: {}", operator);
final long id = operator.start("some", null);
logger.debug("id: {}", id);
final JobExecution execution = operator.getJobExecution(id);
logger.debug("execution: {}", execution);
Проблема в том, что выполнение выполняется асинхронно, а метод main просто возвращается.
Лучшее, что я могу сделать, это зацикливаться, пока состояние выхода не станет нулевым.
String status;
while ((status = execution.getExitStatus()) == null) {
//logger.debug("sleeping");
Thread.sleep(1000L);
}
logger.debug("status: {}", status);
Есть ли другой способ сделать это?
3 ответа
Если вам нужно block-and-wait
, как вы описали, другого варианта нет, но есть что-то вроде awaiCompletion()
реализованы.
Ваш циклический подход может быть улучшен. Давайте использовать ThreadPoolExecutor
В качестве примера. У него есть следующий метод:
/**
* Blocks until all tasks have completed execution after a shutdown
* request, or the timeout occurs, or the current thread is
* interrupted, whichever happens first.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return {@code true} if this executor terminated and
* {@code false} if the timeout elapsed before termination
* @throws InterruptedException if interrupted while waiting
*/
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
и вот реализация:
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
Пожалуйста, обратите внимание:
- бесконечный цикл всегда должен иметь определенное условие выхода
- в вашем случае тайм-аут является обязательным, потому что вряд ли вы готовы к бесконечному ожиданию
- естественно, вы должны знать, был ли это тайм-аут или прекращение работы
Итак, вот адаптированная версия:
public static boolean awaitTermination(JobExecution execution, long timeout) throws InterruptedException {
final long limit = System.currentTimeMillis() + timeout;
for (;;) {
if (null != execution.getExitStatus()) {
return true;
}
if (System.currentTimeMillis() >= limit) {
return false;
}
Thread.sleep(timeout/10);
}
}
JBeret имеет внутренний метод:
org.jberet.runtime.JobExecutionImpl#awaitTermination(long timeout, TimeUnit timeUnit);
для этой цели.
При работе с JBeret вы можете вызвать этот метод для JobExecution, полученного при запуске задания.
Вы можете реализовать класс JobListener или просто расширить AbstractJobListener:
...
public class MyJobListener extends AbstractJobListenerJobListener {
// The afterJob method receives control after the job execution ends.
@Override
public void afterJob() throws Exception { ... }
...
}
А в методе afterJob вы можете использовать базовую технику синхронизации Java (Future или около того).