Java Thread 中断

概念

Java的中断是一种协作机制,也就是说通过中断并不能直接中断另外一个线程,而需要被中断的线程自己处理中断。
在Java的中断模型中,每个线程都有一个boolean标识,代表着是否有中断请求(该请求可以来自所有线程,包括被中断的线程本身)。例如,当线程t1想中断线程t2,只需要在线程t1中将线程t2对象的中断标识置为true,然后线程2可以选择在合适的时候处理该中断请求,甚至可以不理会该请求,就像这个线程没有被中断一样。

中断方法


方法名 介绍
void interrupt() 中断线程,设置线程的中断位true
boolean isInterrupted() 检查线程的中断标记位,true-中断状态, false-非中断状态
static boolean interrupted() 静态方法,返回当前线程的中断标记位,同时清除中断标记,改为false。比如当前线程已中断,调用interrupted(),返回true, 同时将当前线程的中断标记位改为false, 再次调用interrupted(),会发现返回false

中断Sleep 、wait、join方法,会清楚中断标记,不能通过中断标记处理逻辑

阻塞方法sleep响应中断,抛出InterruptedException,同时清除中断标记位为false。

    /**
     * 在中断sleep,wait,join的线程时,会清除中断标记,无法获取中断标记
     * 线程在sleep时被中断,被中断后会抛出InterruptedException异常,并且会清除中断标记,无法获取中断标记
     * @throws InterruptedException e
     */
    public void testSleepThread() throws InterruptedException {
        Thread sleepThread = new Thread(() -> {
            int i = 100;
            boolean stop = false;
            while (i-- > 0 && !stop) {
                log.debug("{} status: [{}]",Thread.currentThread().getName(), Thread.currentThread().isInterrupted());
                log.info("线程执行中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.info("线程被中断");
                    stop = Thread.currentThread().isInterrupted();
                    e.printStackTrace();
                    log.debug("stop status: [{}]", stop);
                }
            }

        }, "sleepThread");
        sleepThread.start();
        Thread.sleep(2000);
        sleepThread.interrupt();
        Thread.sleep(2000);
        log.debug("{} status: [{}]",sleepThread.getName(), sleepThread.isInterrupted());
        Thread.sleep(2000);
    }

img_tc_1702321701421352226.png

正常中断,可以处理中断逻辑

   /**
     * 正常被中断的线程,可以获取中断标记,获取中断标记后处理中断逻辑
     * @throws InterruptedException e
     */
    public void testNormalInterrupt() throws InterruptedException {
        Thread sleepThread = new Thread(() -> {
            int i = 100000;
            boolean stop = false;
            while (i-- > 0 && !stop) {
                stop = Thread.currentThread().isInterrupted();
                log.info("{} status: [{}]",Thread.currentThread().getName(), stop);
                log.info("线程执行中");
                if (stop) {
                    log.info("线程被中断,处理中断逻辑。。。");
                }
            }

        }, "normalInterruptThread");
        sleepThread.start();
        Thread.sleep(3);
        sleepThread.interrupt();
        log.debug("{} status: [{}]",sleepThread.getName(), sleepThread.isInterrupted());
        Thread.sleep(2000);
    }

img_tc_1335541705642553465.png

使用LockSupport.park() 阻塞线程,使用unpark中断唤醒被Park的线程,与interrupt()不冲突,可继续使用interrupt()打断线程

/**
     * 使用LockSupport.park() 阻塞线程,使用unpark中断唤醒被Park的线程,与interrupt()不冲突,可继续使用interrupt()打断线程
     * @throws InterruptedException
     */
    public void testParkThread() throws InterruptedException {
        Thread parkThread = new Thread(() -> {
            log.info("interrupt status: [{}]", Thread.currentThread().isInterrupted());
            log.info("parkThread  park前,等待线程被打断.....");
            LockSupport.park();
            log.info("parkThread 被打断park后.....");
            log.info("interrupt status: [{}]", Thread.currentThread().isInterrupted());
            boolean fla = Thread.currentThread().isInterrupted();
            while (!fla){
                fla = Thread.currentThread().isInterrupted();
                log.info("循环中断标志位[{}]",fla);
                if (fla){
                    log.info("触发中断异常,处理中断逻辑.....");
                }
            }
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
            }
            log.info("parkThread sleep 5000后");
        }, "parkThread");
        parkThread.start();
        Thread.sleep(1000);
        log.info("parkThread unpark前.....");
        LockSupport.unpark(parkThread);
        log.info("parkThread unpark后.....");
        Thread.sleep(1);
        parkThread.interrupt();
        Thread.sleep(5000);
    }

img_tc_1331481705642307964.png