线程终止的条件
函数经由return语句返回,或者出现方法中没有捕获的异常。在java早期版本,有一个stop方法,其他线程可以通过调用它来终止线程,现已废弃。
因此,如今没有可以用来强制结束线程的方法,但有可以用来请求终止线程的方法:interrupt
线程中断的处理
每个线程内部都具有一个boolean标志位,记录这个线程的中断状态。当调用interrupt方法时,中断状态将被置位。
因此,线程应该不时地检查这个标志,以判断线程是否被中断。我们可以调用isInterrupted方法检查标志位。
while(!Thread.currentThread().isInterrupted && do something) {
// do something...
}
注意:interrupted方法和isInterrupted方法在功能上很相似。interrupted方法是静态方法,除了检测当前线程是否被中断,还会清除该线程的中断状态标志位。isInterrupted是实例方法,只会检测当前线程是否被中断。
当线程被阻塞(sleep 或 wait)时,就无法检测中断状态,这时就会产生InterruptedException异常。当然也存在不能被中断的阻塞IO调用,因此应该考虑选择可中断的调用。
不可中断阻塞的情况有如下:
-
java.io包中的同步Socket I/O
-
java.io包中的同步I/O
-
Selector的异步I/O
-
获取某个锁
当检测到中断信号时,我们可以针对该情况做特殊处理,但更普遍的情况是将其作为一个终止的请求。
Runnable r = () -> {
try {
// do something...
while(!Thread.currentThread().isInterrupted() && do something) {
// do something...
}
} catch (InterruptedException e) {
// thread was interrupted during sleep or wait...
} finally {
// clean or something...
}
};
上面这种情况是在阻塞时会因为无法检测而抛出异常。那么,在线程中工作迭代之后调用sleep(wait或其他可中断方法),isInterrupted检测就没有必要和作用了。如果在中断状态被置位时调用sleep方法,不仅不会休眠,而且会重置该状态并抛出InterruptedException。因此,当循环调用sleep时,不要检测中断状态,直接捕获异常。
Runnable r = () -> {
try {
// do something...
while(do something) {
// do something...
Thread.sleep(delay);
}
} catch(InterruptedException e) {
// thread was interrupted during sleep
} finally {
// clean...
}
}
InterruptedException的处理
在业务处理中有sleep等可中断的阻塞方法调用时,除了正常的业务处理场景,当我们不需要做什么的时候,不要什么都不做或者只是打个log,我们应该设置中断状态方便调用者检测,或者更好的选择是,直接抛出给调用者(run方法)
void mySubTask1() {
// do something...
try {
sleep(delay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// do something...
}
void mySubTask2() throws InterruptedException {
// do something...
sleep(delay);
// do something...
}