第5章
Two-phase Termination(两阶段终止)模式
5.1 Two-phase Termination模式简介
停止线程是一个目标简单而实现起来却不那么简单的任务。首先,Java没有提供直接的API用于停止线程[1]。此外,停止线程还有一些额外的细节需要考虑,如待停止的线程处于阻塞(如等待获得锁)或者等待(等待其他线程)状态、尚有未处理完毕的任务等。
Two-phase Termination模式通过将停止线程这个动作分解为准备阶段和执行阶段这两个阶段,提供了一种通用的用于优雅[2]地停止线程的方法。
准备阶段 该阶段的主要动作是“通知”目标线程(待停止的线程)准备停止。这一步会设置一个标志变量用于指示目标线程可以准备停止了。但是,由于目标线程可能正处于阻塞状态(等待获得锁)、等待状态(如调用Object.wait)或者I/O等待(如InputStream.read)等状态,即便设置了这个标志变量,目标线程也无法立即“看到”这个标志变量而做出相应的动作。因此,这一阶段还需要通过调用目标线程的interrupt方法,以期望目标线程能够通过捕获相关的异常而侦测到该方法调用,从而中断其阻塞状态、等待状态。对于能够对interrupt方法调用做出响应的方法(参见表5-1),目标线程代码可以通过捕获这些方法抛出的InterruptedException来侦测线程停止信号。但也有一些方法(如InputStream.read)并不对interrupt方法调用做出响应,此时需要我们手动处理,如在同步的Socket I/O操作中通过关闭Socket,使处于I/O等待状态的Socket抛出java.net.SocketException。
表5-1 能够对Thread.interrupt做出响应的一些方法
执行阶段 该阶段的主要动作是检查准备阶段所设置的线程停止标志变量和信号,在此基础上决定线程停止的时机,并进行适当的“清理”操作。