Java并发-interrupt方法详解

215 阅读3分钟

Interrupt方法详解

1.简介

interrupt方法是Thread类中的一个普通方法,它的作用主要是通知中断当前线程。

  • 当线程处于wait、sleep、join方法阻塞时被中断,则会清除标记状态,并抛出InterruptedException异常
  • 当线程处于正常执行程序时,只会设置标记状态

接下来我们以案例来详细说明interrupt方法以及相关方法的使用。

2.interrupt不起作用的情况

inturrept方法通过设置一个标记状态为true,是否中断线程交由线程内部去处理。如果线程内部不针对这个标记状态做处理,线程是不会中断的,如下图所示。

image.png

代码

线程方法:

@Slf4j  
class MonitorThread1 {  
    private Thread monitorThread;  

    public void start(){  
        monitorThread = new Thread(()->{  
            while(true){  
                log.info("监视线程.......");  
            }  
        },"monitor-thread");  

        monitorThread.start();  
    }  

    public void stop(){  
        monitorThread.interrupt();  
    }  
}

测试主类:

public static void main(String[] args) throws InterruptedException {  
    MonitorThread1 monitorThread = new MonitorThread1();  
    monitorThread.start();  
    Thread.sleep(3500);  
    monitorThread.stop();  
}

运行结果:

image.png

线程会一直运行下,并不会被中断。

3.interrupt方法结合isInterrupted使用

isInterrupted方法是Thread类中的普通方法,作用是返回当前线程的中断标记。

有了这个方法,那我们应该就可以理解了,interrupt方法结合isInterrupted使用就可以中断某个线程了。

image.png

代码

线程方法:

@Slf4j  
class MonitorThread2 {  
    private Thread monitorThread;  

    public void start(){  
        monitorThread = new Thread(()->{  
            while(true){  
                if (Thread.currentThread().isInterrupted()) {  
                    log.info("中断标记为true了,该退出了,退出前可以做一些收尾工作......");  
                    break;  
                }  
                log.info("监视线程.......");  
            }  
        },"monitor-thread");  

        monitorThread.start();  
    }  

    public void stop(){  
        monitorThread.interrupt();  
    }  
}

测试主类:

public static void main(String[] args) throws InterruptedException {  
    MonitorThread2 monitorThread = new MonitorThread2();  
    monitorThread.start();  
    Thread.sleep(5);  
    monitorThread.stop();  
}

输出结果:

image.png

4.interrupt方法结合isInterrupted方法中断sleep方法

这个案例主要用来说明interrupt方法在中断sleep、wait、join方法时会重置中断标记,并抛出InterruptedException异常。

image.png

代码

线程方法:

@Slf4j  
class MonitorThread{  
    private Thread monitorThread;  
  
    public void start(){  
        monitorThread = new Thread(()->{  
            while(true){  
                Thread thread = Thread.currentThread();  
                if(thread.isInterrupted()){  
                    log.info("中断标记为true了,该退出了,退出前可以做一些收尾工作......");  
                    break;  
                }  
                try {  
                    //如果在sleep时触发打断标记,异常被捕获并且清除打断标记  
                    Thread.sleep(1000);  
                    //如果是这里被打断了,不会进异常  
                    log.info("监视线程......");  
                } catch (InterruptedException e) {  
                    //打印一下中断标记状态  
                    System.out.println(thread.isInterrupted());  
                    log.error("",e);  
                }  
            }  
        },"monitor-thread");  
  
        monitorThread.start();  
    }  
  
    public void stop(){  
        monitorThread.interrupt();  
    }  
}

测试主类:

public static void main(String[] args) throws InterruptedException {  
    MonitorThread monitorThread = new MonitorThread();  
    monitorThread.start();  
    Thread.sleep(3500);  
    monitorThread.stop();  
}

输出结果:

image.png

  • 可以看到异常被捕获后,中断标记为false,表示sleep方法处中断时确实清除了中断标记,程序会继续运行

那如果不想让程序继续运行,需要在catch块中再调用一次interrupt方法,让其重新设置中断标记为true。改一下线程方法如下:

image.png


总结

案例中使用interrupt方法结合isInterrupted方法做到中断线程。除了isInterrupted方法外,还有interrupted方法也可以和interrupt方法结合使用。

isInterrupted方法和interrupted方法的区别:

  • 相同点

    • 两者方法调用后都是返回当前线程的中断标记位
  • 不同点

    • isInterrupted是Thread类的普通方法,interrupted是Thread类的静态方法
    • isInterrupted方法返回当前中断标记位后对标记位不再做处理,interrupted方法返回标记位后会将标记位重新置为false