在Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断"
中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如Thread.sleep()
,很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断请求,但是这样做的话会影响响应。
中断的协作特性所带来的一个好处是,它为安全地构造可取消活动提供更大的灵活性。我们很少希望一个活动立即停止;如果活动在正在进行更新的时候被取消,那么程序数据结构可能处于不一致状态。中断允许一个可取消活动来清理正在进行的工作,恢复不变量,通知其他活动它要被取消,然后才终止。
线程中断在线程生命周期中的作用:
线程状态 : :
(1) New(2) Runnable(3) Blocked(4) Dead 死亡。
值得注意的是:(runnable != running )
大家都知道:所有现代桌面和服务器操作系统都使用了抢占式的线程调度策略 。(非常小的运行时间单位)用完以后,不管程序有没有执行完,线程被强制放弃CPU,进入就绪状态,直到下次被调度后开始继续执行。
也就是说,Runnable可运行状态的线程处于两种可能的情况下:
(1)占用CPU运行中,
(2)等待调度的就绪状态。
这里要声明一下:处于等待调度的就绪状态线程和处于阻塞的线程是完全不同的。
就绪的线程是因为时间片用完而放弃CPU,其随时都有可能再次获得CPU而运行,这一切取决于分时OS的线程调度策略。
CPU的情况我们叫做线程中断 。注意这和我们下面要将得中断线程是两个完全不同的概念。事实上,我们不可能通过应用程序来控制CPU的线程中断,除非我们能够自由调用OS的内核。
http://blog.sina.com.cn/s/blog_7a351012010166si.html
如今,Java的线程调度不提供抢占式中断,而采用协作式的中断。其实,协作式的中断,原理很简单,就是轮询某个表示中断的标记
另一方面,利用轮询检查标志变量的方式,想要中断wait和sleep等线程阻塞操作也束手无策。 如果仍然利用上面的思路,要想让中断及时被响应,必须在虚拟机底层进行线程调度的对标记变量进行检查。是的,JVM中确实是这样做的。下面摘自java.lang.Thread的源代码:
代码如下:
可以发现,isInterrupted被声明为native方法,取决于JVM底层的实现。 实际上,JVM内部确实为每个线程维护了一个中断标记。但应用程序不能直接访问这个中断变量,必须通过下面几个方法进行操作:
代码如下:
通常情况下,调用线程的interrupt方法,并不能立即引发中断,只是设置了JVM内部的中断标记。因此,通过检查中断标记,应用程序可以做一些特殊操作,也可以完全忽略中断。
你可能想,如果JVM只提供了这种简陋的中断机制,那和应用程序自己定义中断变量并轮询的方法相比,基本也没有什么优势。
JVM内部中断变量的主要优势,就是对于某些情况,提供了模拟自动“中断陷入”的机制。 在执行涉及线程调度的阻塞调用时(例如wait、sleep和join),如果发生中断,被阻塞线程会“尽可能快的”抛出InterruptedException。因此,我们就可以用下面的代码框架来处理线程阻塞中断:
代码如下:
所谓“尽可能快”,我猜测JVM就是在线程调度调度的间隙检查中断变量,速度取决于JVM的实现和硬件的性能。
通常,中断的使用场景有以下几个:
点击某个桌面应用中的取消按钮时;
某个操作超过了一定的执行时间限制需要中止时;
多个线程做相同的事情,只要一个线程成功其它线程都可以取消时;
一组线程中的一个或多个出现错误导致整组都无法继续时;
当一个应用或服务需要停止时。
http://stackoverflow.com/questions/3976344/handling-interruptedexception-in-java
这样的情景您也许并不陌生:您在编写一个测试程序,程序需要暂停一段时间,于是调用Thread.sleep()
。但是编译器或 IDE 报错说没有处理检查到的InterruptedException
。InterruptedException
是什么呢,为什么必须处理它?对于InterruptedException
,一种常见的处理方式是 “生吞(swallow)” 它 —— 捕捉它,然后什么也不做(或者记录下它,不过这也好不到哪去)—— 就像后面的 清单 4 一样。不幸的是,这种方法忽略了这样一个事实:这期间可能发生中断,而中断可能导致应用程序丧失及时取消活动或关闭的能力。
阻塞方法
当一个方法抛出InterruptedException
时,它不仅告诉您它可以抛出一个特定的检查异常,而且还告诉您其他一些事情。例如,它告诉您它是一个阻塞(blocking)方法,如果您响应得当的话,它将尝试消除阻塞并尽早返回。
阻塞方法不同于一般的要运行较长时间的方法。一般方法的完成只取决于它所要做的事情,以及是否有足够多可用的计算资源(CPU 周期和内存)。而阻塞方法的完成还取决于一些外部的事件,例如计时器到期,I/O 完成,或者另一个线程的动作(释放一个锁,设置一个标志,或者将一个任务放在一个工作队列中)。一般方法在它们的工作做完后即可结束,而阻塞方法较难于预测,因为它们取决于外部事件。阻塞方法可能影响响应能力,因为难于预测它们何时会结束。
阻塞方法可能因为等不到所等的事件而无法终止,因此令阻塞方法可取消Thread
Thread.sleep()
Object.wait()
InterruptedException
InterruptedException
InterruptedException
,以便能够用于可取消活动中,而不至于影响响应。
线程中断
每个线程都有一个与之相关联的 Boolean 属性,用于表示线程的中断状态(interrupted status)。中断状态初始时为 false;当另一个线程通过调用Thread.interrupt()
Thread.sleep()
、Thread.join()
Object.wait()
,那么它将取消阻塞并抛出InterruptedException
。否则,interrupt()
Thread.isInterrupted()
Thread.interrupted()
的操作读取和清除。中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如Thread.sleep()
,很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断请求,但是这样做的话会影响响应。
中断的协作特性所带来的一个好处是,它为安全地构造可取消活动提供更大的灵活性。我们很少希望一个活动立即停止;如果活动在正在进行更新的时候被取消,那么程序数据结构可能处于不一致状态。中断允许一个可取消活动来清理正在进行的工作,恢复不变量,通知其他活动它要被取消,然后才终止。
处理 InterruptedException
如果抛出InterruptedException
InterruptedException
。通常最容易的策略是自己抛出InterruptedException
,如清单 1 中putTask()
getTask()
InterruptedException
添加到 throws 子句。
清单 1. 不捕捉 InterruptedException,将它传播给调用者
有时候需要在传播异常之前进行一些清理工作。在这种情况下,可以捕捉InterruptedException
,执行清理,然后抛出异常。清单 2 演示了这种技术,该代码是用于匹配在线游戏服务中的玩家的一种机制。matchPlayers()
InterruptedException
,这样那个玩家对游戏的请求就不至于丢失。
清单 2. 在重新抛出 InterruptedException 之前执行特定于任务的清理工作
不要生吞中断
有时候抛出InterruptedException
Runnable
InterruptedException
,但是您也不想什么都不做。当一个阻塞方法检测到中断并抛出InterruptedException
InterruptedException
interrupt()
InterruptedException
并且不重新抛出它时,就在返回之前重新中断当前线程。
清单 3. 捕捉 InterruptedException 后恢复中断状态
处理InterruptedException
InterruptedException
也不是明智的做法,因为等到人来读取日志的时候,再来对它作出处理就为时已晚了。) 清单 4 展示了一种使用得很广泛的模式,这也是生吞中断的一种模式:
清单 4. 生吞中断 —— 不要这么做
如果不能重新抛出InterruptedException
,不管您是否计划处理中断请求,仍然需要重新中断当前线程,因为一个中断请求可能有多个 “接收者”。标准线程池 (ThreadPoolExecutor
)worker 线程实现负责中断,因此中断一个运行在线程池中的任务可以起到双重效果,一是取消任务,二是通知执行线程线程池正要关闭。如果任务生吞中断请求,则 worker 线程将不知道有一个被请求的中断,从而耽误应用程序或服务的关闭。
http://www.ibm.com/developerworks/cn/java/j-jtp05236.html