Вопрос по concurrency, java – Как перезапустить расписание, когда scheduleWithFixedDelay выдает исключение?

4

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

ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
this.startMemoryUpdateSchedule(service);//See below method

//Recursive method to handle exception when run schedule task
private void startMemoryUpdateSchedule(ScheduledExecutorService service) {
    ScheduledFuture<?> future = service.scheduleWithFixedDelay(new MemoryUpdateThread(), 1, UPDATE_MEMORY_SCHEDULE, TimeUnit.MINUTES);
    try {
        future.get();
    } catch (ExecutionException e) {
        e.printStackTrace();
        logger.error("Exception thrown for thread",e);
        future.cancel(true);
        this.startMemoryUpdateSchedule(service);
    } catch(Exception e) {
        logger.error("Other exception ",e);
    }
}
@ Паранной, я создам новый поток для этой функции из основного потока. Simon Wang
эй, когда вы вызываете this.startMemoryUpdateSchedule (service) из основного потока. Основному потоку придется ждать завершения процесса, но ваша функция будет работать вечно. Основной поток перейдет в спящий режим ?? Prannoy Mittal

Ваш Ответ

4   ответа
0

public void startMemoryUpdateSchedule(final ScheduledExecutorService service) {

    boolean retry = false;

    do {

        ScheduledFuture<?> future = null;
        try {
            retry = false;
            future = service.scheduleWithFixedDelay(new MemoryUpdateThread(), 1, UPDATE_MEMORY_SCHEDULE, TimeUnit.SECONDS);
            future.get();
        } catch (ExecutionException e) {
            // handle
            future.cancel(true);
            retry = true;
        } catch(Exception e) {
            // handle
        }           

    } while (retry);

}
Error: User Rate Limit Exceeded
1

VerboseRunnable класс отjcabi-журнал, который предназначен именно для этой цели:

import com.jcabi.log.VerboseRunnable;
Runnable runnable = new VerboseRunnable(
  Runnable() {
    public void run() { 
      // do business logic, may Exception occurs
    }
  },
  true // it means that all exceptions will be swallowed and logged
);

Теперь, когда кто-нибудь звонитrunnable.run() исключений не выбрасывается. Вместо этого они проглатываются и регистрируются (в SLF4J).

Error: User Rate Limit Exceeded Simon Wang
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Simon Wang
0

ScheduledExecutorService.scheduleWithFixedDelay(Runnable, long, long, TimeUnit) бросаетRejectedExecutionException (потомок RuntimeException) == & gt; Мы можем поймать это & amp; повторите попытку еще раз.

Сейчас какfuture.get() должен вернуть результат одного выполнения, нам нужно вызвать его в цикле.

Кроме того, сбой одного выполнения не влияет на следующее запланированное выполнение, что отличает ScheduledExecutorService от TimerTask, который выполняет запланированные задачи в том же потоке = & gt; сбой в одном выполнении приведет к прерыванию расписания в случае TimerTask (http://stackoverflow.com/questions/409932/java-timer-vs-executorservice) Нам просто нужно отловить все три исключения, сгенерированные Future.get (), но мы не можем отбросить их, тогда мы не сможем получить результат последующих выполнений.

Код может быть:

public void startMemoryUpdateSchedule(final ScheduledExecutorService service) {
final ScheduledFuture<?> future;
    try {
        future = service.scheduleWithFixedDelay(new MemoryUpdateThread(),
                1, UPDATE_MEMORY_SCHEDULE, TimeUnit.SECONDS);
    } catch (RejectedExecutionException ree) {
        startMemoryUpdateSchedule(service);
        return;
    }
    while (true) {
        try {
            future.get();
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException ee) {
            Throwable cause = ee.getCause();
            // take action, log etc.
        } catch (CancellationException e) {
          // safety measure if task was cancelled by some external agent.
        }
    }
}
1

while(true) цикл, потому что если первый запуск не вызывает исключение, вы выйдете из своего метода, а если второй вызов выбросит один, вы его не поймаете.

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

Так это будет выглядеть так:

private void startMemoryUpdateSchedule(final ScheduledExecutorService service) {
    final ScheduledFuture<?> future = service.scheduleWithFixedDelay(new MemoryUpdateThread(), 1, UPDATE_MEMORY_SCHEDULE, TimeUnit.MINUTES);
    Runnable watchdog = new Runnable() {

        @Override
        public void run() {
            while (true) {
                try {
                    future.get();
                } catch (ExecutionException e) {
                    //handle it
                    startMemoryUpdateSchedule(service);
                    return;
                } catch (InterruptedException e) {
                    //handle it
                    return;
                }
            }
        }
    };
    new Thread(watchdog).start();
}
Error: User Rate Limit Exceededfuture.get()Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Simon Wang
Error: User Rate Limit Exceeded Simon Wang

Похожие вопросы