[bugfix]重新理解Thread的InterruptedException

来源:互联网 发布:大连交通大学网络平台 编辑:程序博客网 时间:2024/06/08 10:27

在前面一篇blog中,错误理解了中断异常,还被评为新手贴,最近找时间认真理解了一下线程的这个异常,呵呵。:

原文在这里。

 

下文部分内容来自dw上的一篇文章,已经贴在附件里面、。

 

下面通过一段代码来演示中断:

 

package thread;/** * created on 2010-4-27下午04:32:40 *  * @author weisong */public class TestInterupt {public static void main(String[] args) throws InterruptedException {Th1 th = new Th1();th.start();Thread.sleep(2000);System.out.println("try to stop");th.interrupt();}}class Th1 extends Thread {public void run(){try {this.sleep(50000);} catch (InterruptedException e) {System.out.println("interrupted ");e.printStackTrace();}}}

 这个简单的代码过程是:启动一个线程th,sleep50s, 然后在main线程中去中断掉它的阻塞状态,然后th就走到catch代码中。

 

现在最主要的关注点有两个:1.走到catch中,th这个线程命运如何?  2.如何处理这个InterruptedException 比较合理。

 

问题一:走到catch中,th这个线程命运如何。

在catch块代码执行完毕之后,th线程会马上终止掉!这个是合理的。当一个方法抛出 InterruptedException 时,它不仅告诉您它可以抛出一个特定的检查异常,而且还告诉您其他一些事情。例如,它告诉您它是一个阻塞(blocking)方法,如果您响应得当的话,它将尝试消除阻塞并尽早返回。 阻塞方法不同于一般的要运行较长时间的方法。一般方法的完成只取决于它所要做的事情,以及是否有足够多可用的计算资源(CPU 周期和内存)。而阻塞方法的完成还取决于一些外部的事件,例如计时器到期,I/O 完成,或者另一个线程的动作(释放一个锁,设置一个标志,或者将一个任务放在一个工作队列中)。一般方法在它们的工作做完后即可结束,而阻塞方法较难于预测,因为它们取决于外部事件。阻塞方法可能因为等不到所等的事件而无法终止,因此令阻塞方法可取消 就非常有用

 

那么也就不难理解, Thread.sleep()Object.wait() 为什么会抛出这个InterruptedException。目的就是支持中断取消机制;它允许一个线程请求另一个线程停止它正在做的事情。当一个方法抛出 InterruptedException 时,它是在告诉您,如果执行该方法的线程被中断,它将尝试停止它正在做的事情而提前返回,并通过抛出 InterruptedException 表明它提前返回。

 

问题二。我们如何去处理InterruptedException 

 

中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如 Thread.sleep(),很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。您可以随意忽略中断请求,但是这样做的话会影响响应。

 

那么就产生下面几个应用情况了:

1. 不捕捉 InterruptedException,将它传播给调用者。向上抛出,自己不处理。

2. 在重新抛出 InterruptedException 之前执行特定于任务的清理工作(比如连接关闭之类)

3. 捕捉 InterruptedException 后恢复中断状态

 

public class TaskRunner implements Runnable {    private BlockingQueue<Task> queue;    public TaskRunner(BlockingQueue<Task> queue) {         this.queue = queue;     }    public void run() {         try {             while (true) {                 Task task = queue.take(10, TimeUnit.SECONDS);                 task.execute();             }         }         catch (InterruptedException e) {              // Restore the interrupted status             Thread.currentThread().interrupt();         }    }}

 4.需要中断阻塞线程, 那么参考最上面的demo,直接走完catch流程不处理异常即可。

 

ps.不可中断的阻塞方法

并非所有的阻塞方法都抛出 InterruptedException。输入和输出流类会阻塞等待 I/O 完成,但是它们不抛出 InterruptedException,而且在被中断的情况下也不会提前返回。然而,对于套接字 I/O,如果一个线程关闭套接字,则那个套接字上的阻塞 I/O 操作将提前结束,并抛出一个 SocketExceptionjava.nio 中的非阻塞 I/O 类也不支持可中断 I/O,但是同样可以通过关闭通道或者请求 Selector 上的唤醒来取消阻塞操作。类似地,尝试获取一个内部锁的操作(进入一个 synchronized 块)是不能被中断的,但是 ReentrantLock 支持可中断的获取模式。

 

原创粉丝点击