抓住Java Throwable重启线程的最佳方法

时间:2018-05-22 09:20:53

标签: java multithreading try-catch throwable

我在java中有以下代码 -

@Override
public void run() {

    logger.info("Thread Started:" + this.getName());

    try {
        runJob();
    } catch( Throwable e) {
        logger.error("Exception in running thread: " + this.getName() + ", restarting job", e);
        run();
    }
}

public void runJob() {

    while(true) {
       try {
           // Work here
       } catch(Exception e) {
           // log the exception
       }
    }
 }

这段代码实际上是否会在每种情况下保持线程活动,这只是恢复线程的方法吗?

这是我在阅读完所有答案后想到的另一种选择。让我知道,即使发生错误,这是一个永远保持线程活着的好方法:

@Override
public void run() {

    logger.info("Thread Started:" + this.getName());

    while(true) {
      try {
        runJob();
      } catch( Throwable e) {
        logger.error("Exception in running thread: " + this.getName() + ", restarting job", e);
        }
    }
}

public void runJob() {

     try {
          // Work here
     } catch(Exception e) {
          // log the exception
     }
 }

3 个答案:

答案 0 :(得分:7)

这与“线程”没什么关系。可以在异常上实现重试逻辑,这是常见的做法。

然而,抓住Throwable显然是一件危险的事情。您可能希望重试选择错误(例如超时,连接失败等),这当然需要更好地了解runJob()方法的运行方式。

除此之外,您的重试实施正在进行递归调用,这也可能很糟糕。你最终会遇到堆栈溢出错误(并catch它与你的Throwbale catch块一起,总共会导致奇怪的行为)。而是反复循环并执行runJob()

boolean retry = false;
do {
    try {
        runJob();
        retry = false;
    } catch (SpecificException e) { //timeout, network failure exceptions
        logger.error("Exception in running thread: "
            + this.getName() + ", restarting job");
        retry = true;
    }
} while(retry);

您可能还需要添加计数器来限制重试次数。

答案 1 :(得分:3)

您永远不应该使用try-catch控制流量!

此外,如果你在catch中调用这个失败的方法,它将再次被调用,导致递归的无休止循环,因此StackOverflowError

我建议您创建一个计数器来限制最大尝试次数。 对于这个用例,请从问题How do you implement a re-try-catch?

中获得灵感

有许多库提供恢复机制。我推荐你jcabi-aspects

答案 2 :(得分:3)

它不会“恢复”它,而是重新开始并再试一次。这可能会导致无限循环的递归调用,直到发生StackOverflow。在这种情况下,无论如何都会停止您的申请。

想象一下,访问一个不存在的文件(由于拼写错误或其他原因)。您总是会抓住FileNotFoundException并重新尝试一次又一次地读取同一个不存在的文件......

在不改变任何事情的情况下一遍又一遍地重复同一任务几乎总会导致相同的异常并且上述情况发生。正确的异常处理总是比在任何情况下保持程序更为重要。让您的软件用户知道问题所在。也许这是他可以改变的事情。也许不吧。在任何情况下,最好中止线程而不是递归重新开始。