Как я могу синхронизировать выполнение 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 или около того).

Другие вопросы по тегам