阻塞方法和中断方法

  线程可能会阻塞或者暂停执行,原因有多种:等待I/O操作结束,等待获得一个锁,等待从Thread.sleep方法中醒来,或是等待另一个线程的计算结果。当线程阻塞时,它通常被挂起,并处于某种阻塞状态(BLOCKED, WAITING或TIMED_WATING)。阻塞操作与执行时间很长的普通操作的差别在于,被阻塞的线程必须等待某个不受它控制的事件发生后才能继续执行,例如等待I/O操作完成,等待某个锁变成可用,或者等待外部计算的结束。当某个外部事件发生时,线程被置回RUNNABLE状态,并可以再次被调度执行。
  BlockingQueue的put和take等方法会抛出受检查异常InterruptedException。当某方法抛出InterruptedException时,表示该方法是一个阻塞方法。如果这个方法被中断,那么它将努力提前结束阻塞状态。
Thread提供了interrupt方法,用于中断线程或者查询线程是否已经被中断。每个线程都有一个布尔类型的属性,表示线程的中断状态,当中断线程时将设置这个状态。
  中断是一种协作机制。一个线程不能强制其他线程停止正在执行的操作。当线程A中断B时,A仅仅是要求B在执行到某个可以暂停的地方停止正在执行的操作,前提是B线程愿意停止下来。通常使用中断的情况就是取消某个操作。方法对中断的响应越高,就越容易及时取消那些执行时间很长的操作。
  当在代码中调用了一个将抛出InterruptedException异常的方法时,你自己的方法也就变成了一个阻塞方法,并且必须处理对中断的响应。
  对于库代码来说,有两种基本选择:
  1、传递InrerruptedException。不捕获该异常,或者捕获该异常,然后简单处理好再次抛出异常。
  2、恢复中断。有时候不能抛出异常,如当代码是Runnable的一部分时。在这些情况下,必须捕获InteruptedException,并通过调用当前线程上的interrupt方法恢复中断状态,这样在调用栈更高层的代码中将看到已发了一个中断,如下面所示

public class TaskRunnable implements Runnable{
    BlockingQueue<Task> queue;
    ...
    public void run{
        try{
            processTask(queue.take());
        }catch(InterruptedException e){
           Thread.currentThread().interrupt();
        }
    }
}    


  在出现InterruptedException时不应该捕获它但不做出任何响应,导致更高层代码无法对中断采取措施,因为中断信息已经丢失。只有扩展Thread代码,并且能控制调用栈上所有高层代码,才能屏蔽中断。

 

  关于如何处理InterruptedException,可以参考  Java 理论与实践 处理 InterruptedException 捕捉到它,然后怎么处理它?

posted @ 2017-07-02 22:08  lwli  阅读(3655)  评论(0编辑  收藏  举报