如何处理InterruptedException异常

InterruptedException简单描述

InterruptedException异常是一个经常被误解的异常,通常情况下我们会忽视或则转化成RuntimeException并抛出:throw new RuntimeException(e);然而这种做法通常都是不正确的。

InterruptedException出现一般都是因为在线程执行的时候被打断(interrupt),线程(A)不是自己打断自己,一般都是在另外一个线程(B)中执行中断方法(objA.interrupt())。

每个线程都管理一个自己的中断状态(interruption status),它可以通过Thread#interrupt()方法设置位中断状态,或则使Thread#interrupted()重置状态。另外,Thread#isInterrupted()通常用来判断是否处以中断状态。

程序的状态

RUNNABLE: 程序正在运行,其他线程能够调度它.
BLOCKED, WAITING or TIMED_WAITING:线程等待中,等待一些像超时等事件的发生.

当线程处于RUNNABLE状态的时候,通过Thread.currentThread.isInterrupted()判断中断状态,并终止程序循环执行:

class ComplicatedCalculator implements Runnable {
  @Override
  public void run() {
    while (!Thread.currentThread.isInterrupted()) {
      // calculate something here
    }
  }
}

当线程处在BLOCKED, WAITING or TIMED_WAITING状态的时候,考虑以下程序,如何判断sleep正常执行完而没有被中断,也许可以通过sleep返回一个状态来判断,但是这增加了处理判断该状态的负担,所以sleep设计成了当抛出InterruptedException异常的方式来处理中断(这里拿Thread.sleep做示例,其他的也一样)。

class Simulation implements Runnable {
  @Override
  public void run() {
    while (!Thread.currentThread.isInterrupted()) {
      // ... simulation calculations here ...
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        // empty
      }
    }
  }
}

处理InterruptedException异常的常用方法:

  • Rethrow:重新抛出,一般对blocking结果操作(如:BlockingQueue)直接重新抛出。
class BlockQueueTest {
    ArrayBlockingQueue<Integer> testQueue = new ArrayBlockingQueue<Integer>(4);

    public int poll() throws InterruptedException {
        return testQueue.poll(10, TimeUnit.SECONDS);
    }

    public void put() throws InterruptedException {
        testQueue.put(1);
    }
}
  • Catch, restore and terminate:像Runnable这种不能Rethrow异常,通常做法是catch异常,然后恢复中断状态,然后立即终止。
    注意: sleep被打断后会重置中断状态并抛出InterruptedException异常,也就是说当sleep catch住的代码块中,当前线程已经不是中断状态了,如果要终止程序,需要调用Thread.currentThread.interrupt(),Thread.currentThread.interrupt()就是将线程restore的意思了。
class Simulation implements Runnable {
  @Override
  public void run() {
    while (!Thread.currentThread.isInterrupted()) {
      // ... simulation calculations here ...
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        // restore interruption status of the corresponding thread
        Thread.currentThread.interrupt();
      }
    }
  }
}
  • Catch and terminate:这是上面一种方式的变种,像Thread的子类,已经是调用栈(不太懂)的最上层调用,没有人关系它的中中断状态,可以直接终止进程了。
    以下程序是我猜测这种处理方式的意思(不知道对不对):
class Simulation extend Thread {
  @Override
  public void run() {
    while (true) {
      // ... simulation calculations here ...
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        // terminate
        return;
      }
    }
  }
}

个人感言(可以忽略):在方法或代码出现中断异常,如果不会对后面程序照成影响的话,我一般都记warn级别的日志(不知道对不对)。


线程池中断线程

通常情况下会通过调用Future#cancel(true)来发送中断请求。

ExecutorService e = Executors.newFixedThreadPool(4);
Future<?> f = e.submit(simulation);
// ...
// now cancel the running simulation
f.cancel(true);

参考文献

http://daniel.mitterdorfer.name/articles/2015/handling-interruptedexception/

转自:https://blog.csdn.net/kanbuqinghuanyizhang/article/details/52668978
 
原文地址:https://www.cnblogs.com/javalinux/p/14298446.html