Java 异常 InterruptedException

Java 在调用 wait() 或者 sleep() 方法时,需要处理中断异常 InterruptedException。我们需要了解为什么会出现这个异常,以及如何避免出现这样的异常。

基础回顾

中断异常 InterruptedException 是在多线程条件下出现的,在 Java 中,应用程序从一个与main()方法相关联的线程(称为主线程)开始,然后这个主线程可以启动其他线程。

下面是线程的生命周期:

一旦我们创建了一个新线程,它就处于新建(NEW)状态。它一直保持这种状态,直到程序调用 start() 方法启动线程。

调用 start() 方法会将其置于就绪(RUNNABLE)状态。处于此状态的线程要么正在运行,要么已准备好运行。

当一个线程正在等待锁并试图访问被其他线程锁定的代码时,它会进入阻塞(BLOCKED)状态。

可以通过各种事件将线程置于暂停(WAITING)状态,例如调用wait()方法。在这种状态下,一个线程正在等待来自另一个线程的信号。

当线程完成执行或异常终止时,它将以死亡(TERMINATED)状态结束。线程可以被中断,当一个线程被中断时,它会抛出InterruptedException。

理解 InterruptedException

如果线程在等待、休眠或以其他方式被占用时被中断,则会引发InterruptedException。换句话说,一些代码在我们的线程上调用了 Interrupt()方法。

为什么会存在中断系统呢?中断方法允许开发者在程序运行过程中,暂时挂起任务。例如某些操作是IO密集型任务或者一个耗时的计算,中断后可以让出CPU资源。

InterruptedException通常由所有阻塞方法抛出,以便可以处理它并执行纠正操作。Java 中有几种抛出InterruptedException的方法,例如 Thread.sleep()、Thread.join()、Object.wait()方法,以及BlockingQueue的put()和take()方法。

中断方法

Thread 类中提供了一些关于中断的关键方法:

public void interrupt() { ... }
public boolean isInterrupted() { ... }
public static boolean interrupted() { ... }

interrupt() 方法可以用来中断线程。还有两个方法都可以用来判断线程是否被中断,使用时可能存在困惑。

isInterrupted 与 interrupted

从源码看,他们两者有一定关系。

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
    return isInterrupted(false);
}

private native boolean  isInterrupted(boolean ClearInterrupted);
  • isInterrupted 与 interrupted 都返回布尔值
  • 都是用来判断线程是否被中断
  • 二者最终的值都由 native 的 isInterrupted 决定
  • isInterrupted 为实例方法,用来检查调用它的 Thread
  • interrupted 为静态方法,用来检查当前 Thread
  • interrupted 会清除中断状态,连续调用两次该方法,无论第一次返回什么,第二次一定返回 false
  • isInterrupted 不会清除中断状态,连续调用两次该方法,返回值一定相同
  • interrupted 好像是在询问,之前是否调用过interrupt()
  • isInterrupted 好像是在询问,调用它的线程当前是否被中断

处理 InterruptedException

线程间的调度依赖 JVM,而 JVM 的多线程需要操作系统底层来处理。因此,虽然我们能通过代码中断线程,但无法保证何时被中断,也不能保证一定能中断。

中断是给线程的指令,告诉它应该停止正在做的事情而去做其他事情。中断以后,我们还需要有程序能响应中断,避免出现死锁的情况。

throws

我们可以给需要处理中断的方法添加 throws 来向上抛出异常,让调用者确定如何处理该中断。

public static void stopHere() throws InterruptedException {
    Thread.sleep(1000);
}

当然,这样需要确保最终是有方法处理该异常,否则在最后,程序执行到该处代码时,会直接将 InterruptedException 抛出而导致程序意外结束。

catch

处理异常的第二种方式就是捕获该异常并处理掉。

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

一种处理方式为再次调用 interrupt(),以便调用堆栈中更高层级的代码可以看到发出了中断。

转载请注明出处:码谱记录 » Java 异常 InterruptedException
标签: