4

I use ScheduledExecutorService to schedule some tasks which need to run periodically. I want to know whether this code works to recover the schedule when an exception happens.

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

while(true)最初の実行で例外がスローされない場合はメソッドを終了し、2番目の呼び出しで例外がスローされた場合はキャッチされないため、おそらくtryブロックをループで囲む必要があります。

また、問題が発生した場合に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 (a child of RuntimeException) ==> We can catch it & retry submission once more.

Now as future.get() is supposed to return the result of one execution, we need to invoke it in a loop.

Also, the failure of one execution does not affect the next scheduled execution, which differentiates the ScheduledExecutorService from the TimerTask which executes the scheduled tasks in the same thread => failure in one execution would abort the schedule in case of TimerTask (http://stackoverflow.com/questions/409932/java-timer-vs-executorservice) We just need to catch all the three exceptions thrown by Future.get(), but we can not rethrow them, then we won't be able to get the result of the subsequent executions.

The code could be:

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

Try to use VerboseRunnable class from jcabi-log, which is designed exactly for this purpose:

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

Now, when anybody calls runnable.run() no exceptions are thrown. Instead, they are swallowed and logged (to SLF4J).

于 2013-04-06T05:36:25.200 に答える
0

I've added the loop as discussed.

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 に答える