ScheduledExecutorServiceexception处理
我使用ScheduledExecutorService定期执行一个方法。
p代码:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); ScheduledFuture<?> handle = scheduler.scheduleWithFixedDelay(new Runnable() { public void run() { //Do business logic, may Exception occurs } }, 1, 10, TimeUnit.SECONDS); 我的问题:
 如何继续调度程序,如果run()抛出exception? 我应该尝试在方法run()捕获所有exception? 或者任何内置的callback方法来处理exception? 谢谢! 
 您应该使用scheduler.scheduleWithFixedDelay(...)返回的ScheduledFuture对象,如下所示: 
 ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); ScheduledFuture<?> handle = scheduler.scheduleWithFixedDelay(new Runnable() { public void run() { throw new RuntimeException("foo"); } }, 1, 10, TimeUnit.SECONDS); // Create and Start an exception handler thread // pass the "handle" object to the thread // Inside the handler thread do : .... try { handle.get(); } catch (ExecutionException e) { Exception rootException = e.getCause(); } 
问题
 这个问题涉及到ScheduledExecutorService的关键技巧: 任何抛出exception或到达执行程序的错误都会导致执行程序停止。  Runnable没有更多的调用,没有更多的工作完成。 这个工作停顿是悄然发生的,你不会被通知。 这个顽皮的博客张贴有趣地叙述了难以了解这种行为的方式。 
解决scheme
yegor256的回答和arun_suresh的回答似乎基本上是正确的。 两个问题与这些答案:
- 捕获错误以及例外
- 有点复杂
错误和例外?
在Java中,我们通常只捕获exception ,而不是错误 。 但是在这个ScheduledExecutorService的特殊情况下,如果没有捕获任何一个,将意味着停工。 所以你可能要抓住两个。 我不是100%肯定这一点,不完全知道捕捉所有错误的影响。 如果需要,请纠正我。
捕获exception和错误的一种方法是捕获它们的超类Throwable 。
 } catch ( Throwable t ) { 
…而不是…
 } catch ( Exception e ) { 
 最简单的方法:只需添加一个Try-Catch 
但是这两个答案都有点复杂。 为了logging,我将展示最简单的解决scheme:
总是将你的Runnable的代码封装在Try-Catch中,以捕获任何exception和错误。
Lambda语法
使用lambda(在Java 8和更高版本中)。
 final Runnable someChoreRunnable = () -> { try { doChore(); } catch ( Throwable t ) { // Catch Throwable rather than Exception (a subclass). logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() ); } }; 
古板的语法
老式的方式,在lambda之前。
 final Runnable someChoreRunnable = new Runnable() { @Override public void run () { try { doChore(); } catch ( Throwable t ) { // Catch Throwable rather than Exception (a subclass). logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() ); } } }; 
在每个可运行/可调用中
 无论ScheduledExecutorService如何,在Runnable 任何 run方法中总是使用一般try-catch( Exception† e )似乎是明智的。 对于Callable任何call方法,同上。 
  †或者也许Throwable而不是Exception来捕获Error对象。 
 另一个解决scheme是吞下Runnable的exception。 您可以使用jcabi-log中的方便的VerboseRunnable类,例如: 
 import com.jcabi.log.VerboseRunnable; scheduler.scheduleWithFixedDelay( new VerboseRunnable( Runnable() { public void run() { // do business logic, may Exception occurs } }, true // it means that all exceptions will be swallowed and logged ), 1, 10, TimeUnit.SECONDS ); 
 我知道这是一个老问题,但是如果有人使用ScheduledExecutorService延迟CompletableFuture ,那么应该这样处理: 
 private static CompletableFuture<String> delayed(Duration delay) { CompletableFuture<String> delayed = new CompletableFuture<>(); executor.schedule(() -> { String value = null; try { value = mayThrowExceptionOrValue(); } catch (Throwable ex) { delayed.completeExceptionally(ex); } if (!delayed.isCompletedExceptionally()) { delayed.complete(value); } }, delay.toMillis(), TimeUnit.MILLISECONDS); return delayed; } 
 并在CompletableFuture处理exception: 
 CompletableFuture<String> delayed = delayed(Duration.ofSeconds(5)); delayed.exceptionally(ex -> { //handle exception return null; }).thenAccept(value -> { //handle value });