《Java核心技术卷》读书笔记-并发(二)- 线程中断

64 阅读2分钟

线程终止的条件

函数经由return语句返回,或者出现方法中没有捕获的异常。在java早期版本,有一个stop方法,其他线程可以通过调用它来终止线程,现已废弃。

因此,如今没有可以用来强制结束线程的方法,但有可以用来请求终止线程的方法:interrupt

线程中断的处理

每个线程内部都具有一个boolean标志位,记录这个线程的中断状态。当调用interrupt方法时,中断状态将被置位。

因此,线程应该不时地检查这个标志,以判断线程是否被中断。我们可以调用isInterrupted方法检查标志位。


while(!Thread.currentThread().isInterrupted && do something) {

// do something...

}

注意:interrupted方法和isInterrupted方法在功能上很相似。interrupted方法是静态方法,除了检测当前线程是否被中断,还会清除该线程的中断状态标志位。isInterrupted是实例方法,只会检测当前线程是否被中断。

当线程被阻塞(sleep 或 wait)时,就无法检测中断状态,这时就会产生InterruptedException异常。当然也存在不能被中断的阻塞IO调用,因此应该考虑选择可中断的调用。

不可中断阻塞的情况有如下:

  1. java.io包中的同步Socket I/O

  2. java.io包中的同步I/O

  3. Selector的异步I/O

  4. 获取某个锁

当检测到中断信号时,我们可以针对该情况做特殊处理,但更普遍的情况是将其作为一个终止的请求。


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...

}