1.什么情况下会考出InterruptedException?

Interrupt从字面意思看貌似是说,当一个线程运行到一半,将它中断,然后会抛出InterruptedException异常,然而并不是这样。

只有声明了会抛出InterruptedException的函数才会抛出异常。如下:

public static native void sleep(long millis) throws InterruptedException{...}

public final void wait() throws InterruptedException{...}

public final void join() throws InterruptedException{...}

2.轻量级阻塞与重量级阻塞

轻量级阻塞:能够被中断的阻塞,对应的线程状态是WAITTING或者TIMED_WAITTING。

重量级阻塞:不能被中断的阻塞,对应状态是BLOCKED。像synchronized这种。

如下图,是调用不同函数之后,一个线程完整的状态迁移过程。

Java并发原理-线程的状态迁移过程

初始线程处于NEW状态,调用start()之后开始执行,进入RUNNING或者READY状态。如果没有调用任何阻塞函数,线程只会在RUNNING和READY状态切换,即系统的时间片调度。这两种状态切换是由操作系统完成的,开发者基本没有机会介入,除了调用yield()函数,放弃对CPU的占用。

一旦调用了图中的任何函数,线程就会进入WAITTING或者TIMED_WAITTING状态,两者区别只是前者为无限期阻塞,后者传入了一个时间参数,阻塞了一个有限的时间。如果使用了synchronized关键字或者synchronized块,则会进入BLOCKED状态。

除了常见的阻塞/唤醒函数,还有一对不太常见的阻塞/唤醒函数,LockSupport.park() 和 LockSupport.unpark()。这对函数非常重要,Concurrent包中的Lock的实现即依赖这一对儿操作原语。

故而t.interrupted()函数的精确含义是“唤醒轻量阻塞”,而不是“中断一个线程”。

3. t.interrupted()和Thread.interrupted()的区别

因为t.interrupted()相当于给线程发送了一个唤醒的信号,所以如果线程此时恰好处于WAITTING或者TIMED_WAITTING状态,就会抛出一个InterrutedException,并且线程被唤醒。而如果线程此时没有被阻塞,则线程什么都不会做。但在后续,线程可以判断自己是否收到过其它线程发来的中断信号,然后做一些对应的处理。

这两个函数都是线程用于判断自己是否收到过中断信号的,前者是非静态函数,后者是静态函数。二者的区别在于,前者只是读取中断状态,不修改状态;后者不仅读取中断状态,还会重置中断标志位。