为什么仅从sleep()和wait()等阻塞方法抛出InterruptedException?

时间:2017-05-06 17:17:57

标签: java multithreading wait sleep interrupted-exception

如果我编写如下代码,我们不能中断或终止线程。它也不会抛出InterruptedException。

Thread loop = new Thread(
  new Runnable() {
    @Override
    public void run() {
      while (true) {
      }
    }
  }
);
loop.start();
loop.interrupt();

要中断此线程,我需要修改我的代码,如下所示:

Thread loop = new Thread(
  new Runnable() {
    @Override
    public void run() {
      while (true) {
        if (Thread.interrupted()) {
          break;
        }
        // Continue to do nothing
      }
    }
  }
);
loop.start();
loop.interrupt();

我的问题是,

  1. 为什么Java的设计方式只有在阻塞方法如sleep()和wait()的情况下才会抛出 InterruptedException

  2. 为什么在普通代码中,我们需要像上面的代码片段一样手动处理?每当我们通过 interrupt()方法设置中断标志时,为什么Java不会抛出InterruptedException?

  3. 我读过很多关于InterruptedException的博客和文章,但还没有找到令人信服的答案。

    修改

    在InterruptedException上找到了很好的文章: http://codepumpkin.com/interruptedexception-java-multithreading/

2 个答案:

答案 0 :(得分:3)

  

1)为什么Java的设计方式只有在阻塞方法如sleep()和wait()的情况下才会抛出InterruptedException。

thread.interrupt()的全部意义在于它是合作的。线程被中断,但它必须使用Thread.currentThread().isInterrupted()检查中断标志,以便它可以正确管理它自己的终端,并在必要时清理共享对象,锁,最后块等。

引用tutorial on the subject,强调我的。

  

中断是一个线程的指示,它应该停止它正在做的事情并做其他事情。由程序员确定线程如何响应到中断是,但线程终止是很常见的。

抛出InterruptedException的方法是等待锁和其他条件的方法。这些说它们被中断了,所以线程可以在终止之前自行清理。

  

2)为什么在普通代码中,我们需要像上面的代码片段一样手动处理?每当我们通过interrupt()方法设置中断标志时,为什么Java不会抛出InterruptedException?

替代方案是让InterruptedException成为RuntimeException,无论程序是否预期,都可以随时抛出。 stop()和其他已弃用的Thread方法的部分问题在于它们往往违反各种语言结构,并且可能会离开 应用程序内存处于不良状态。这是more details about that

InterruptedException如果是RuntimeException,也可以这样说。你可以想象一个线程是在改变一个共享对象,然后只是在中游引发一个意外的RuntimeException或者完全停止了。正在更新的共享对象很容易处于无效状态。

if (Thread.interrupted()) {

这不是正确的调用方法,因为它会清除线程上的中断标志,这是一个错误的模式。请使用以下内容:

if (Thread.currentThread().isInterrupted()) {

这样可以保留中断标志,如果可能的话应该这样做。此外,当抛出InterruptedException时,也会清除中断标志。这就是为什么这是一个很好的模式:

try {
   ...
} catch (InterruptedException ie) {
   // re-interrupt the thread to propagate the interrupt flag
   Thread.currentThread().interrupt();
   // handle the interrupt here by probably quitting the thread
}

库存在“吞下”中断标志的问题很多。即使您的代码很小,它也可能被复制到一个更大的块中,因此您总是可以将中断标志恢复为良好的模式。

答案 1 :(得分:1)

早期版本的Java曾经能够杀死线程,但在尝试支持多个操作系统时很快就成了问题。 操作系统有很多不同的方法实现具有非常不同功能的线程。 在飞行途中停止线程被认为是不安全的,可能导致应用程序的其他部分出现意外行为,例如死锁。

此处有更多详情: https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html