多线程系列提高(8)--取消与关闭

来源:互联网 发布:cas java 编辑:程序博客网 时间:2024/06/06 09:47

任务和线程的启动很容易,然后让它们运行直到结束,或者让它们自行停止。但是,如果我们希望提前结束任务或者线程,或者是因为用户取消了当前操作,或者应用程序需要被快速的关闭。Java中没有提供任何机制来安全的终止线程,但它提供了中断,这是一种协作机制,能够使一个线程终止另一个线程的当前工作。
这种协作式的方法是必要的,我们很少希望某个任务、线程或服务立即停止,因为这种立即停止会使共享的数据结构处于不一致的状态。相反,在编写任务和服务时可以使用一种协作的方法:当需要停止时,它们首先会清除当前正在执行的工作,然后再结束。

一、中断

线程中断是一种协作机制,线程可以通过这种机制来通知另一个线程,告诉它在合适的或者可能的情况下停止当前工作,并转而执行其它的工作。
每个线程都要一个boolean类型的中断状态。当线程中断时,这个线程的中断状态将被设置为true,在Thread中包含了中断线程以及查询线程中断状态的方法,如下面代码所示

//Thread中的中断方法public class Thread{    public void interrupt(){...}    public boolean isInterrupted(){...}    public static boolean interrupted(){...}    ......}

interrupt()方法能中断目标线程,而isInterrupted()方法能返回目标线程的中断状态。静态的interrupted方法将清除当前线程的中断状态,并返回它之前的值,这也是清除中断状态的唯一方法。

阻塞库方法,例如Thread.sleep和Object.wait方法等,都会检查线程何时中断,并且在发现中断时提前返回。它们在响应中断时执行的操作包括:清除中断状态,抛出InterruptedException,表示阻塞操作由于中断而提前结束。JVM并不能保证阻塞方法检测到中断的速度,但在实际情况中响应速度还是非常快的。

对中断操作的正确理解是:它并不会真正的中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己。(这些时刻也被称为取消点)。有些方法,例如wait、sleep和join等,将严格的处理这种请求,当它们收到中断请求或者在开始执行时发现某个已被设置好的中断状态时,将抛出一个异常。设计良好的方法可以完全忽略这种请求,只要它们能使调用代码对中断请求进行某种处理。设计糟糕的方法可能会屏蔽中断请求,从而导致调用栈中国的其它代码无法对中断请求做出响应。
通常,中断是实现取消的最合理的方式。

二、中断策略

中断线程规定线程如何解释某个中断请求–当发现中断请求时,应该做哪些工作(如果需要的话),哪些工作单元对于中断来说是原子操作,以及以多快的速度来响应中断。
最合理的中断策略是某种形式的线程级(Thread-Level)取消操作或服务级(Service-Level)取消操作:尽快退出,在必要时进行清理,通知某个所有者该线程已经退出。此外还可以建立其它的中断策略,例如暂停服务或重新开始服务,但对于那些包含非标准中断策略的线程或线程池,只能用于能知道这些策略的任务中。
当检查到中断时,任务并需要放弃所有的操作–它可以推迟处理中断请求,并直到某个更合适的时刻,因此需要记住中断请求,并在完成当前任务后抛出InterruptedException或者表示已收到中断请求。这项技术能够确保在更新过程中发生中断时,数据结构不会被破坏。
如果除了将InterruptedException传递给调用者外还需要执行其它操作,那么应该在捕获InterruptedException之后恢复中断状态:

Thread.currentThread().interrupt();

三、响应中断

当调用可中断的阻塞函数时,例如Thread.sleep或BlockingQueue.put等,有两种实用策略可用于处理InterruptedException:
传递异常:可能在执行某个特定于任务的清除操作之后,从而使你的方法也成为可中断的阻塞方法。
恢复中断方法:从而使调用栈中的上层代码能够对其进行处理。

0 0
原创粉丝点击