Two-phase Termination直译的话是“两相终止”,不过就这个模式而言,该译作“两阶段终止”比较适当,想像您有一个执行绪正在周期性的运作,在“运作阶段”您送出了停止执行绪的请求,这时候执行绪不该慌张的马上终止目前的工作,而是先完成这一次周期的工作,然后进入“善后阶段”完成一些善后的工作,例如关闭档案或网路串流,所谓的两阶段终止,即中止“运作阶段”,并完成“善后阶段”,完整的完成执行绪的工作。
以Java的Thread终止而言,不建议您直接使用stop()方法来终止执行绪,stop()方法会丢出ThreadDeath例外强迫执行绪终止,即使执行绪正在运作阶段或执行至synchronized区,如果您要终止执行绪,建议自行实作,例如:
private boolean isTerminated = false;
public void terminate() {
isTerminated = true;
}
public void run() {
while(!isTerminated) {
// ... some statements
}
}
}
考虑到有时执行绪可能会执行至sleep()或wait()而进入Not Runnable状态,使用上面的方法可能会延迟终止的请求,因而可以在要求终止时再呼叫interrupt()方法,这会丢出 InterruptedException,而使得执行绪从Not Runnable状态中离开,因此可以改变一下程式:
private boolean isTerminated = false;
public void terminate() {
isTerminated = true;
interrupt();
}
public void run() {
try {
while(!isTerminated) {
// ... some statements
}
}
catch(InterruptedException e) {
}
}
}
在发出中止请求之后,如果执行绪是在Not Runnable状态,会丢出InterruptedException,如果这个例外没有先被捕捉,就会被run()中的catch InterruptedException捕捉,也就是说会直接离开while回圈,因而如果您在发出终止请求后,要求先执行完这一个周期的工作,您要先捕捉这个例外,若不用完成这一个周期的工作,则不用捕捉这个例外,要如何作取决于您的程式。
如果执行绪要完成这一个周期的工作,在下一个周期开始之前检查旗标,这时它的结果是false,所以离开while回圈,这时候您可以进行一些善后工作,这个可以写在finally区块中,例如:
private boolean isContinue = false;
public void terminate() {
isTerminated = true;
interrupt();
}
private void doWorkBeforeShutdown() {
// .... do some work before shutdown
}
public void run() {
try {
while(!_isTerminated) {
// ... some statements
}
}
catch(InterruptedException e) {
}
finally {
doWorkBeforeShutdown();
}
}
}
上面这个程式大致上就是Two-phase Termination模式的架构,另外如果您的执行绪还服务着其它的物件,则在送出终止请求到完全终止之前,应该停止服务其它物件,您可以让其它物件要求服务之前,先查询执行绪是否已被要求终止,这可以藉由提供一个方法来达到:
private boolean isTerminated = false;
public void terminate() {
isTerminated = true;
interrupt();
}
public boolean isTerminated() {
return _isTerminated;
}
private void doWorkBeforeShutdown() {
// .... do some work before shutdown
}
public void run() {
try {
while(!_isTerminated) {
// ... some statements
}
}
catch(InterruptedException e) {
}
finally {
doWorkBeforeShutdown();
}
}
}