CountDownLatch InterruptedException

15

我正在使用CountDownLatch来在两个线程之间同步初始化过程,我想知道它可能抛出的InterruptedException的正确处理方式。

我最初编写的代码是这样的:

    private CountDownLatch initWaitHandle = new CountDownLatch(1);
    /**
     * This method will block until the thread has fully initialized, this should only be called from different threads  Ensure that the thread has started before this is called.
     */
    public void ensureInitialized()
    {
        assert this.isAlive() : "The thread should be started before calling this method.";
        assert Thread.currentThread() != this, "This should be called from a different thread (potential deadlock)";
        while(true)
        {
            try
            {
                //we wait until the updater thread initializes the cache
                //that way we know 
                initWaitHandle.await();
                break;//if we get here the latch is zero and we are done
            } 
            catch (InterruptedException e)
            {
                LOG.warn("Thread interrupted", e);
            }
        }
    }

这个代码模式有意义吗?基本上,忽略InterruptedException并继续等待直到成功,这是一个好主意吗?我想我只是不理解在什么情况下会发生中断,所以我不知道是否应该以不同的方式处理它们。

为什么会在这里抛出InterruptedException,如何最佳实践处理它?

2个回答

12

这正是你不应该为InterruptedException做的事情。一个InterruptedException基本上是一个礼貌的请求,要求线程终止。线程应尽快清理并退出。

IBM发布了一篇很好的文章:http://www.ibm.com/developerworks/java/library/j-jtp05236.html

以下是我会做的:

// Run while not interrupted.
while(!(Thread.interrupted())
{
    try
    {
        // Do whatever here.
    }
    catch(InterruptedException e)
    {
        // This will cause the current thread's interrupt flag to be set.
        Thread.currentThread().interrupt();
    }
}

// Perform cleanup and exit thread.

这种做法的优点在于:如果你的线程在阻塞方法中被中断,那么中断位将不会被设置并且将抛出InterruptedException异常。如果你的线程在非阻塞方法中被中断,中断位将被设置,但不会抛出任何异常。因此,通过调用interrupt()方法来设置异常标志,两种情况都被归一化为第一种情况,并由循环条件进行检查。

作为额外的奖励,这还让您可以通过简单地中断它来停止您的线程,而不是发明自己的机制或接口来设置某个布尔标志以执行完全相同的操作。


啊,我试图修复你的格式,但出现了编辑冲突。我无法回滚。抱歉! - Mark Peters
我已经回滚了。感谢您的帮助!虽然我注意到了这个问题,但我还是决定在写完长篇大论之后一起解决。 - jdmichal
实际上不是,我只是非常习惯于维基百科,在那里你可以在要撤消的编辑上点击回滚,而不是要回滚到的修订版本上。 - Mark Peters
我可以补充jdmichal的回答,你应该始终考虑当线程(即应用程序的逻辑任务)被中断时该怎么做--你可以尝试重新启动/继续这些任务,或者回滚它们并向应用程序的上一级报告失败。 - Victor Sorokin
非常感谢。那篇文章很棒。我一定会实现这个的。我想我处理InterruptedExceptions的方式已经错了很长时间了。 - luke
IBM的文章目前无法访问,我提供了一个缓存版本:https://web.archive.org/web/20201217182342/https://www.ibm.com/developerworks/java/library/j-jtp05236/index.html - JRr

4

如果您没有预见到任何合理的原因导致Thread被中断,也想不出任何合理的应对措施,我建议您应该这样做

 catch (InterruptedException e){
      throw new AssertionError("Unexpected Interruption",e);
 }

这样,如果发生这种中断,应用程序将明显失败,使其更容易在测试期间发现。然后您可以考虑应用程序应如何处理,或者设计中是否存在任何问题。


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