当前位置: 代码迷 >> 综合 >> 线程中断——interrupt()
  详细解决方案

线程中断——interrupt()

热度:35   发布时间:2023-12-22 03:46:17.0

1、interrupt()说明:根据api的说明,在线程处于中断状态时调用大部分的阻塞方法可能会抛异常

Interrupts this thread.Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.If none of the previous conditions hold then this thread's interrupt status will be set.Interrupting a thread that is not alive need not have any effect.

2、中断线程的方式

①调用interrupt()方法并不会真正的中断线程,只是改变了线程的中断状态,示例:

public class InterruptSelf {public static void main(String[] args) {InnerThread it = new InnerThread();it.start();}static class InnerThread extends Thread {@Overridepublic void run() {for (int i = 0;; i++) {System.out.println("子线程运行中...");if (i == 2) {System.out.println("子线程中断前:" + Thread.currentThread().isInterrupted());interrupt();System.out.println("子线程中断后:" + Thread.currentThread().isInterrupted());return;}}}}
}//结果
子线程运行中...
子线程运行中...
子线程运行中...
子线程中断前:false
子线程中断后:true

由结果可知:在调用了interrupt()方法之后,依然打印出了“子线程中断后:true”这句话,说明调用interrupt()并没有使线程中断,但是调用interrupt()方法前后的中断状态改变了,从示例中也可以看出来想真正中断线程需要将run()方法return

②那应该在什么时候将run()方法return呢?也就是说我们怎么知道一个线程应该被中断了呢?这就需要用中断状态作为判断,一个线程无论是自己在run()中调用interrupt()还是在别的线程中通过该线程对象调用interrupt(),那么该线程的中断状态一定是true,我们就可以借助这个状态判断是不是该中断该线程,示例:

public class InterruptedTest extends Thread {public void run() {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("Someone interrupted me.");return;}System.out.println("Going...");long now = System.currentTimeMillis();while (System.currentTimeMillis() - now < 1000);}}public static void main(String[] args) throws InterruptedException {InterruptedTest t = new InterruptedTest();t.start();Thread.sleep(2000);t.interrupt();System.out.println("主线程结束...");}
}//结果
Going...
Going...
Going...
主线程结束...
Someone interrupted me.

③如果在A线程中调用了B线程的interrupt()之后B线程由于欲阻塞自己(比如休眠)而出现了异常,这时怎么中断线程B呢?可以在B线程的run()中捕获异常,在catch代码块中不加状态判断直接return(如果是在循环体中也可以使用break,但此时只是跳出了循环体而让线程正常结束),示例:

sleep:

public class InterruptSelf {public static void main(String[] args) {InnerThread1 it1 = new InnerThread1();it1.start();it1.interrupt();}static class InnerThread1 extends Thread {@Overridepublic void run() {for (;;) {System.out.println("子线程1运行中...");try {System.out.println(">>>异常前:" + Thread.currentThread().isInterrupted());Thread.sleep(1000);} catch (InterruptedException e) {System.out.println(">>>异常后:" + Thread.currentThread().isInterrupted());return;}}}}}//结果
子线程1运行中...
>>>异常前:true
>>>异常后:false

wait: 

public class InterruptSelf {public static void main(String[] args) {InnerThread1 it1 = new InnerThread1();it1.start();it1.interrupt();}static class InnerThread1 extends Thread {@Overridepublic synchronized void run() {for (;;) {System.out.println("子线程1运行中...");try {System.out.println(">>>异常前:" + Thread.currentThread().isInterrupted());wait(1000);} catch (InterruptedException e) {System.out.println(">>>异常后:" + Thread.currentThread().isInterrupted());return;}}}}}//结果
子线程1运行中...
>>>异常前:true
>>>异常后:false

注意:

a、这里在捕捉到InterruptedException异常后并没有加线程是否处于中断状态的判断直接将线程return,这是因为线程在抛出InterruptedException异常前会将中断状态由true改为false,这一点根据打印结果也可以看出来,因此此处在catch到InterruptedException异常后中断状态肯定是false,加判断没有意义

b、并不是线程处于阻塞状态时去中断线程会报异常,而是相反,是在线程处于中断状态(isInterrupted()值为true)时再使其阻塞会报异常,也就是说不能阻塞一个处于中断状态的线程

综上所述:欲中断一个线程,只需要在适当的时候判断线程的中断状态然后return即可,因此可以在一些耗时的操作或者循环体内加上如下判断:

if(interrupted())return;

3、与stop()的比较

interrupt()与stop()的区别在于:它并不像stop方法那样会中断一个正在运行的线程,而只是改变中断状态的标识。线程会不时地检测中断标识位,以判断线程是否应该被中断,stop()方法太过于暴力,会强行把执行一半的线程终止,这样就不能保证线程占用的资源得到正确释放,通常是没有给予线程完成资源释放的机会,因此会导致程序工作在不确定的状态下,因此Thread中的stop()和suspend()方法,由于固有的不安全性,已经建议不再使用

interrupt()这一方法实际完成的是:给受阻塞的线程发出一个中断信号,这样受阻线程就得以退出阻塞的状态。 更确切的说,如果线程被Object.wait()、Thread.join()或Thread.sleep()三种方法之一阻塞,此时调用该线程的interrupt()方法,那么该线程将抛出一个InterruptedException中断异常(该线程必须事先预备好处理此异常),从而提早地终结被阻塞状态。如果线程没有被阻塞,这时调用interrupt()将不起作用

4、interrupted()和isInterrupted()的区别

这两个方法都可以获取到当前线程的中断状态,不同的是使用interrupted()之后该线程的中断状态会被重新置为false,表示该线程已被中断过,使用isInterrupted()则不会重置线程的中断状态,示例:

public class InterruptSelf {public static void main(String[] args) {InnerThread1 it1 = new InnerThread1();it1.start();}static class InnerThread1 extends Thread {@Overridepublic void run() {System.out.println(Thread.currentThread().isInterrupted());interrupt();if (isInterrupted())System.out.println(Thread.currentThread().isInterrupted());if (interrupted())System.out.println(Thread.currentThread().isInterrupted());}}
}//结果
false
true
false

 

  相关解决方案