首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ScheduledExecutorService异常处理

ScheduledExecutorService异常处理
EN

Stack Overflow用户
提问于 2011-08-01 13:45:21
回答 8查看 45.8K关注 0票数 67

我使用ScheduledExecutorService定期执行一个方法。

p-code:

代码语言:javascript
复制
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> handle =
        scheduler.scheduleWithFixedDelay(new Runnable() {
             public void run() { 
                 //Do business logic, may Exception occurs
             }
        }, 1, 10, TimeUnit.SECONDS);

我的问题是:

如果run()抛出异常,如何继续调度?我是否应该尝试捕获方法run()中的所有异常?或者任何内置的回调方法来处理异常?谢谢!

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2011-08-01 14:02:18

您应该像这样使用scheduler.scheduleWithFixedDelay(...)返回的ScheduledFuture对象:

代码语言:javascript
复制
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();
}
票数 33
EN

Stack Overflow用户

发布于 2014-07-23 12:44:45

tl;dr

任何对run方法进行转义的异常都会在没有通知的情况下停止所有后续的工作

始终在run方法中使用 try-catch。如果您希望计划的活动继续,请尝试恢复。

代码语言:javascript
复制
@Override
public void run ()
{
    try {
        doChore();
    } catch ( Exception e ) { 
        logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + t.getStackTrace() );
    }
}

问题所在

这个问题涉及到ScheduledExecutorService的关键技巧:任何抛出的异常或错误到达executor都会导致executor停止。不再调用Runnable,不再完成任何工作。此工作停止是静默发生的,您将不会收到通知。这个顽皮的语言blog posting有趣地讲述了学习这种行为的艰难过程。

解决方案

answer by yegor256answer by arun_suresh似乎都是基本正确的。这些答案有两个问题:

  • 捕获错误以及异常
  • 有点复杂的

错误和异常?

在Java语言中,我们通常只捕获exceptions,而不捕获errors。但在ScheduledExecutorService的这种特殊情况下,没有捕捉到任何一个都将意味着工作停止。所以你可能想同时抓住这两个。我不是百分之百确定这一点,因为我不完全知道捕获所有错误的含义。如果需要,请纠正我。

捕获错误和异常的一个原因可能涉及在任务中使用库。请参阅comment by jannis

捕获异常和错误的一种方法是捕获它们的超类,例如Throwable

代码语言:javascript
复制
} catch ( Throwable t ) {

…而不是…

代码语言:javascript
复制
} catch ( Exception e ) {

最简单的方法:只需添加Try-Catch

但是这两个答案都有点复杂。为了记录在案,我将展示最简单的解决方案:

总是将Runnable的代码包装在Try-Catch中,以捕获任何和所有的异常和错误。

Lambda语法

使用lambda (在Java8和更高版本中)。

代码语言:javascript
复制
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() );
    }
};

老式语法

传统的方式,在lambdas之前。

代码语言:javascript
复制
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是什么,对我来说,在run的任何Runnable方法中总是使用通用try-catch( Exception† e )似乎是明智的。Callable的任何call方法也是如此。

完整的示例代码

在实际工作中,我可能会单独定义Runnable,而不是嵌套。但这是一个整洁的一体化的例子。

代码语言:javascript
复制
package com.basilbourque.example;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 *  Demo `ScheduledExecutorService`
 */
public class App {
    public static void main ( String[] args ) {
        App app = new App();
        app.doIt();
    }

    private void doIt () {

        // Demonstrate a working scheduled executor service.
        // Run, and watch the console for 20 seconds.
        System.out.println( "BASIL - Start." );

        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture < ? > handle =
                scheduler.scheduleWithFixedDelay( new Runnable() {
                    public void run () {
                        try {
                            // doChore ;   // Do business logic.
                            System.out.println( "Now: " + ZonedDateTime.now( ZoneId.systemDefault() ) );  // Report current moment.
                        } catch ( Exception e ) {
                            // … handle exception/error. Trap any unexpected exception here rather to stop it reaching and shutting-down the scheduled executor service.
                            // logger.error( "Caught exception in ScheduledExecutorService. StackTrace:\n" + e.getStackTrace() );
                        }   // End of try-catch.
                    }   // End of `run` method.
                } , 0 , 2 , TimeUnit.SECONDS );


        // Wait a long moment, for background thread to do some work.
        try {
            Thread.sleep( TimeUnit.SECONDS.toMillis( 20 ) );
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }

        // Time is up. Kill the executor service and its thread pool.
        scheduler.shutdown();

        System.out.println( "BASIL - Done." );

    }
}

运行时。

BASIL Start。

现在: 2018-04-10T16:46:01.423286-07:00America/Los_Angeles

现在: 2018-04-10T16:46:03.449178-07:00America/Los_Angeles

现在: 2018-04-10T16:46:05.450107-07:00America/Los_Angeles

现在: 2018-04-10T16:46:07.450586-07:00America/Los_Angeles

现在: 2018-04-10T16:46:09.456076-07:00America/Los_Angeles

现在: 2018-04-10T16:46:11.456872-07:00America/Los_Angeles

现在: 2018-04-10T16:46:13.461944-07:00America/Los_Angeles

现在: 2018-04-10T16:46:15.463837-07:00America/Los_Angeles

现在: 2018-04-10T16:46:17.469218-07:00America/Los_Angeles

现在: 2018-04-10T16:46:19.473935-07:00America/Los_Angeles

罗勒做的。

另一个例子

这是另一个例子。在这里,我们的任务应该运行大约20次,每5秒运行一次,每分钟运行一次。但是在第五次运行时,我们抛出了一个异常。

代码语言:javascript
复制
public class App2
{
    public static void main ( String[] args )
    {
        ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
        final AtomicInteger counter = new AtomicInteger( 0 );
        Runnable task = ( ) -> {
            int c = counter.incrementAndGet();
            if ( c > 4 )
            {
                System.out.println( "THROWING EXCEPTION at " + Instant.now() );
                throw new IllegalStateException( "Bogus exception. c = " + c + ". " + Instant.now() ); // Notice how this exception is silently swallowed by the scheduled executor service, while causing a work stoppage.
            }
            System.out.println( "Task running. c = " + c + ". " + Instant.now() );
        };
        ses.scheduleAtFixedRate( task , 0 , 5 , TimeUnit.SECONDS );

        try { Thread.sleep( Duration.ofMinutes( 1 ).toMillis() ); }catch ( InterruptedException e ) { e.printStackTrace(); }
        System.out.println( "Main thread done sleeping. " + Instant.now() );

        ses.shutdown();
        try { ses.awaitTermination( 1 , TimeUnit.MINUTES ); }catch ( InterruptedException e ) { e.printStackTrace(); }
    }
}

运行时。

代码语言:javascript
复制
Task running. c = 1. 2021-10-14T20:09:16.317995Z
Task running. c = 2. 2021-10-14T20:09:21.321536Z
Task running. c = 3. 2021-10-14T20:09:26.318642Z
Task running. c = 4. 2021-10-14T20:09:31.318320Z
THROWING EXCEPTION at 2021-10-14T20:09:36.321458Z
Main thread done sleeping. 2021-10-14T20:10:16.320430Z

注意:

  • 该异常被调度的executor服务静默接受。
  • 发生工作停止。我们的任务没有进一步的执行计划。再一次,这是一个无声的问题。

因此,当你的任务抛出异常时,你会得到最坏的结果:没有任何解释的静默停止工作。

如上所述,解决方案是:始终在run方法中使用try-catch

Throwable代替Exception来捕获Error对象,也可以使用†。

票数 131
EN

Stack Overflow用户

发布于 2012-05-10 23:47:30

另一种解决方案是在Runnable中接受一个异常。您可以使用jcabi-log中方便的VerboseRunnable类,例如:

代码语言:javascript
复制
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
);
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6894595

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档