在Java中,总是忽略InterruptedException调用Thread sleep()是否安全?

6
在开发一个项目时,我遇到了这段代码,它是用于生产系统的:
public static void sleepUntil(long millisecondToWake) {
    while (true) {
        long currentMillisecond = System.currentTimeMillis();
        if (currentMillisecond >= millisecondToWake) {
            break;
        }
        try {
            Thread.sleep(millisecondToWake - currentMillisecond);
        }
        catch (InterruptedException ignoredException) {
            // do nothing
        }
    }
}

我一直坚持不丢弃异常的基本原则,这也是Joshua Bloch在《Effective Java》中提出的,并得到了我自己广泛经验的支持,因为我曾经不得不调试某些其他人丢弃异常的代码。迄今为止,我还没有发现一个好主意的情况(有时捕获已检查的异常并抛出运行时异常是可以辩论的,但我在这里不谈论这些情况)。

感谢您提供任何评论。


首先,永远不是一个好的选择留下一个空缺。首先,您可能不会注意到代码的故障。阅读产生此异常的情况,并编写期望异常的代码。 - logoff
https://dev59.com/yXRA5IYBdhLWcg3wyRJ7 - Mister Smith
2个回答

5
这里有一篇关于这个特定异常的好文章: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html 基本上,不应该忽略它,代码至少应该传播中断:
catch (InterruptedException e) { 
    // Restore the interrupted status
    Thread.currentThread().interrupt();
}

作者并不在意他的线程被打断的睡眠状态(这是忽略异常的有效理由);然而,当其他线程需要打断时,可能会在作者编写代码时没有预料到或考虑到:

无论您是否计划对中断请求进行操作,您仍希望重新打断当前线程,因为单个中断请求可能有多个“收件人”。标准线程池(ThreadPoolExecutor)工作线程实现对中断响应,因此中断在线程池中运行的任务可能同时取消该任务并通知执行线程线程池正在关闭。


你的代码示例没有传播异常,这很奇怪。 - JB Nizet
我认为作者的想法是让线程休眠,而不必担心处理异常。并不是赞同或者辩护这种做法,只是希望得到更多有见识的意见。我确实读了IBM的文章,但它没有特别涉及sleep的情况。如果最糟糕的情况是JVM在sleep结束之前无法存在,那么我认为这段代码的作者会接受,但我想知道它是否会引起更严重的问题。谢谢! - codeotaku
@JBNizet一点也不奇怪。我没有提到传播异常,而是说要传播中断。 - StuPointerException
我已经更新了我的答案,包括更多的细节。忽略异常的危险大多是无害的,除非我从一个依赖于中断执行某些重要任务的线程中调用此代码; 在这种情况下,我将开始看到奇怪的行为! - StuPointerException
是的,我自己也认为在这种情况下它是无害的,但是放弃任何异常的做法让我感到非常不舒服,因此我希望它比那更糟糕,因为我正在试图建立一个反对这段代码的案例,以便我可以让它改变。然而,就目前而言,我不认为我会赢得这个争论。哦,好吧。 - codeotaku
似乎没有回答原帖的问题。在Thread.sleep()的情况下,直接忽略异常有什么问题吗?假设调用者不关心中断。 - Charles Roth

3
在这个特定的例子中,这种方法似乎是不合理的。特别地,如果用户想要退出程序(例如),JVM会一直挂起直到你的睡眠方法结束,这似乎是不合理的。
在我看来,唯一可以安全忽略InterruptedException的情况是:
- 你完全控制执行你的方法的线程,并且 - 在忽略异常后立即退出。
在任何其他情况下,你应该:重置中断标志并及时退出。
例如,以下代码是可以的:
//the task is local, nobody else can access it
final Runnable localRunnable = new Runnable() {
    public void run() {
        //catch, ignore and exit immediately
        try { Thread.sleep(10000); } catch (InterruptedException e) {}
    }
}
//it is your own thread and you have full control over it
new Thread(localRunnable).start();

除了阻止JVM立即退出之外,还有其他不良可能的结果吗?无论如何,InterruptedException真正表示什么?这对我来说也不清楚。谢谢。 - codeotaku
@codeotaku 中断是Java中用于请求线程停止正在执行的机制。例如,如果一个线程正在下载大文件并且您中断该线程,则应该期望它停止下载,清理资源(关闭套接字等)并退出。当任务忽略中断时,它变得不可能停止。例如,有许多关于第三方库忽略中断并使它们非常不友好的SO问题。在这种情况下,唯一的解决方法是在其自己的进程中运行代码,这会不必要地复杂化事情... - assylias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接