线程中断-interrupt
# 线程中断-interrupt
Thread类提供了中断线程的相关API
- interrupt():中断线程
- interrupted():Thread静态方法,测试当前线程是否已中断。通过该方法可以清除线程的中断状态。换句话说,如果这个方法被连续调用两次,第二个调用将返回false(除非当前线程再次被中断,在第一个调用清除其中断状态之后,在第二个调用检查它之前)。返回结果:如果当前线程已被中断,则为True;否则false。
- isInterrupted():thread实例方法,测试此线程是否已被中断。该方法与interrupted相似,但不清除线程的清除线程的中断状态。
注意,线程中断并不是说将线程停止,而是“唤醒”,可以理解为是中断线程当前的状态,将其唤醒。
# isInterrupted与interrupted
区别:
- interrupted()是Thread静态方法,isInterrupted()是thread实例方法。
- interrupted()会清除线程的中断状态,可能抛异常
InterruptedException
,而isInterrupted()不影响线程的中断状态。
thread.interrupted()相当于给线程发送了一个唤醒的信号,所以如果线程此时恰好处于WAITING
或者TIMED_WAITING
状态,就会抛出一个InterruptedException,并且线程被唤醒。而如果线程此时并没有被阻塞,则线程什么都不会做。但在后续,线程可以判断自己是否收到过其他线程发来的中断信号,然后做一些对应的处理。
这两个方法都是线程用来判断自己是否收到过中断信号的,前者是实例方法,后者是静态方法。二者的区别在于,前者只是读取中断状态,不修改状态;后者不仅读取中断状态,还会重置中断标志位。
# InterruptedException
什么情况下会抛出InterruptedException?
只有那些声明了会抛出InterruptedException的函数才会抛出异常,例如sleep、wait、join:
public static native void sleep(long millis) throws InterruptedException {...}
public final void wait() throws InterruptedException {...}
public final void join() throws InterruptedException {...}
假设while循环中没有调用任何的阻塞函数,就是通常的算术运算,或者打印一行日志,这个时候,在主线程中调用一thread.interrupt()
,该线程并不会抛出异常。如下所示:
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
Thread.sleep(10);
// 中断线程
myThread.interrupt();
Thread.sleep(100);
System.exit(0);
}
}
class MyThread extends Thread {
@Override public void run() {
while (true) {
boolean interrupted = isInterrupted();
System.out.println("中断标记:" + interrupted);
}
}
}
# 轻量级阻塞与重量级阻塞
能够被中断的阻塞称为轻量级阻塞,对应的线程状态是WAITING
或者TIMED_WAITING
;而像synchronized
这种不能被中断的阻塞称为重量级阻塞,对应的状态是 BLOCKED。
如图所示:调用不同的方法后,一个线程的状态迁移过程,状态说明见 线程生命周期
初始线程处于NEW
状态,调用start()开始执行后,进入RUNNING
或者READY
状态。如果没有调用任何的阻塞函数,线程只会在RUNNING
和READY
之间切换,也就是系统的时间片调度。这两种状态的切换是操作系统完成的,除非手动调用yield()
函数,放弃对CPU的占用。
一旦调用了图中的任何阻塞函数,线程就会进入WAITING
或者TIMED_WAITING
状态,两者的区别只是前者为无限期阻塞,后者则传入了一个时间参数,阻塞一个有限的时间。如果使用了synchronized
关键字或者synchronized
块,则会进入BLOCKED状态。
不太常见的阻塞/唤醒函数:LockSupport.park()/unpark()
。这对函数非常关键,Concurrent包中Lock的实现即依赖这一对操作原语。
因此thread.interrupted()的精确含义是“唤醒轻量级阻塞”,而不是字面意思“中断一个线程”。