interrupt()方法是中断线程吗?
不是的。
重点:interrupt()方法是给其它线程设置中断状态,不是指给当前线程设置中断状态。
误解:很多人都认为线程的”中断”就是让线程停止。如果你也这么认为,那你对多线程编程还没有入门。
在java中,线程的中断(interrupt)只是改变了线程的中断状态,至于这个中断状态改变后带来的结果,那是无法确定的,有时它更是让停止中的线程继续执行的唯一手段,不但不是让线程停止运行,反而是继续执行线程的手段。
对于执行一般逻辑的线程,如果调用它的interrupt()方法,那么对这个线程没有任何影响,比如线程a正在执行:
while(条件) x++;
这样的语句,如果其它线程调用a.interrupt(),并不会影响a对象上运行的线程。但是如果在其它线程里测试a的中断状态,那么它已经改变为已中断状态,但并不会停止这个线程的运行。
什么会受到interrupt()的影响?
在一个线程对象上调用interrupt()方法,真正有影响的是以下三个方法(包括它们的重载方法):
- wait()
- join()
- sleep()
注意,上面这三个方法都会抛出InterruptedException异常,记住这句话,下面我会重复。
一个线程在调用interrupt()后,自己不会抛出InterruptedException异常。所以你看到interrupt()并没有抛出这个异常,我上面说如果线程a正在执行如下代码:
while(条件) x++
调用a.interrupt()后,线程会继续正常地执行下去。
但是,如果一个线程被调用了interrupt()后,它的状态是已中断的。这个状态对于正在执行wait(),join(),sleep()的线程,却改变了线程的运行结果。
-
对于wait()中等待notify()/notifyAll()唤醒的线程来说,其实这个线程已经”暂停”执行,因为它正在某一对象的休息室中,这时如果它的中断状态被改变,那么它就会抛出异常。
这个InterruptedException异常不是线程抛出的,而是wait()方法。也就是在wait状态下会发现已被中断的线程,然后抛出InterruptedException异常。意思就是这个线程不能再等待了,其意义就等同于唤醒它了。
-
对于sleep()中的线程,如果你调用了Thread.sleep(“一年”)。现在你后悔了,想让它早些醒过来,调用interrupt()方法就是唯一手段。只有改变它的中断状态,让它从sleep()中将控制权转到处理异常的catch语句中,然后再在catch中的处理正常的逻辑。同样,对于join()中的线程你也可以这样处理。
被notify()的线程和被interrupt()的线程执行有什么区别?
-
被notify()/notifyAll()唤醒的线程会继续执行wait()下面的语句;
-
在wait()中被interrupt()的线程则将控制权交给了catch语句。一些正常的逻辑要被放到catch中来运行,但有时这是唯一手段。
比如一个线程a在某一对象b的wait()中等待唤醒,其它线程必须获取到对象b的监视锁才能调用b.notify()/b.notifyAll(),否则你就无法唤醒线程a,但在任何线程中可以无条件地调用a.interrupt()来达到这个目的。只是唤醒后的逻辑你要放在catch中。当然同notify()/notifyAll()一样,继续执行a线程的条件还是要等拿到b对象的监视锁。
interrupt()可以用来做什么?
在已经调用这三个方法的线程上调用interrupt()方法让它从这几个方法的”暂停”状态中恢复过来。这个恢复过来就可以包含两个目的:
-
使线程继续执行
在catch语句中执行醒来后的逻辑,或由catch语句转回正常的逻辑。总之它是从wait(),sleep(),join()的暂停状态活过来了。
-
使线程停止运行
在catch中什么也不处理,或return。那么就完成了当前线程的使命,可以使在上面”暂停”的状态中立即真正的”停止”。