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);
    }
}
4

4 回答 4

2

您可能应该将 try 块包含在一个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();
}
于 2012-05-30T10:27:41.560 回答
1

ScheduledExecutorService.scheduleWithFixedDelay(Runnable, long, long, TimeUnit)throws RejectedExecutionException(RuntimeException 的一个子项)==> 我们可以捕获它并再次重试提交。

现在future.get()应该返回一次执行的结果,我们需要在循环中调用它。

此外,一次执行失败不会影响下一次计划执行,这将 ScheduledExecutorService 与 TimerTask 区分开来,后者在同一线程中执行计划任务 => 一次执行失败将在 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.
        }
    }
}
于 2012-05-31T07:05:39.793 回答
1

尝试使用专门为此目的设计的jcabi-logVerboseRunnable中的类:

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)。

于 2013-04-06T05:36:25.200 回答
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);

}
于 2012-05-30T11:47:31.570 回答