行业资讯 2025年08月6日
0 收藏 0 点赞 221 浏览 4097 个字
摘要 :

文章目录 1、打断线程阻塞状态 2.打断正常线程 3.(终止)模式之两阶段终止 3.1. 错误思路 3.2. 两阶段终止模式 4.interrupted()方法 5.interrupt打断park线程 6. 总结 ……




  • 1、打断线程阻塞状态
  • 2.打断正常线程
  • 3.(终止)模式之两阶段终止
    • 3.1. 错误思路
    • 3.2. 两阶段终止模式
  • 4.interrupted()方法
  • 5.interrupt打断park线程
  • 6. 总结

本文主要讲解Java线程interrupt方法相关内容,我们一起来学习一下吧!

虽然有很多同学学过了java线程相关的知识,但是对interrupt始终不能深入理解,我们将会通过案例来实操讲解下interrupt的作用。

1、打断线程阻塞状态

interrupt可以打断线程的阻塞状态,在线程调用sleep、wait和join方法进入阻塞状态时,我们可以通过调用线程的interrupt方法来将其打断,线程将会被唤醒并抛出InterruptedException中断异常,我们看下下面的代码:

@Slf4j
public class ThreadInterrupt {
    @Test
    public void testInterrupt(){
        // 创建t1线程
        Thread t1 = new Thread(()->{
            log.debug(\"t1 start\");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                log.debug(\"t1 interrupt\");
                e.printStackTrace();
            }
            log.debug(\"t1 over\");
        },\"t1\");
        // 启动
        t1.start();
        // 主线程休眠1s保证t1进入sleep状态
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断
        t1.interrupt();
        // 确保中断结束
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug(\"t1 中断标记:{}\", t1.isInterrupted());
    }
}

运行输出如下:Java线程interrupt方法详解

我们发现中断最后中断标记为false,是因为interrupt在打断sleep、wait和join方法后会将中断标记重新置为false,如果你在上述代码中,如果删除打印中断标记前的sleep,有机会在抛出中断异常之前打印出中断标记为true的情况,因为interrupt方法有如下两个特点:

  • Thread.interrupt()方法用于中断一个线程。当调用此方法时,将设置线程的中断标志位为true。
  • 如果目标线程正在被阻塞(如在sleep、wait或join方法中)或者正在等待获取一个内置锁(如synchronized块或方法),那么它将抛出一个InterruptedException异常,并清除线程的中断状态,也就是会将中断标志为置为false。

2.打断正常线程

interrupt方法除了可以打断阻塞的线程,还可以打断结束正常的线程,而且方式还比较优雅,我们先看以下代码:

public static void main(String[] args) {
        // 创建t1线程
        Thread t1 = new Thread(()->{
            while (true) {
                System.out.println(\"running\");
            }
        },\"t1\");
        // 启动
        t1.start();
        // 主线程休眠1s保证t1运行起来
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断
        t1.interrupt();
    }

你会发现t1线程会陷入死循环打印,即使interrupt被调用,也不会停止运行,因此想要停止线程,我们需要判断中断标志位,来退出循环结束线程:

public static void main(String[] args) {
        // 创建t1线程
        Thread t1 = new Thread(()->{
            while (true) {
                // 判断打断标志位,若为true退出循环
                boolean isInterrupted = Thread.currentThread().isInterrupted();
                if(isInterrupted) {
                    break;
                }
                System.out.println(\"running\");
            }
        },\"t1\");
        // 启动
        t1.start();
        // 主线程休眠1s保证t1运行起来
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断
        t1.interrupt();
    }

这样我们可以优雅地结束线程的运行了。

3.(终止)模式之两阶段终止

两阶段终止:英文称为Two Phase Termination

即:在一个线程 T1 中如何“优雅”终止线程 T2?这里的【优雅】指的是给 T2 一个料理后事的机会。

3.1. 错误思路

● 使用线程对象的 stop() 方法停止线程
○ stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
● 使用 System.exit(int) 方法停止线程
○ 目的仅是停止一个线程,但这种做法会让整个程序都停止

3.2. 两阶段终止模式

Java线程interrupt方法详解我们先创建一个监控线程类:

@Slf4j
public class TwoPhaseTermination {

    /**
     * 监控线程
     */
    private Thread monitor;

    /**
     * 启动监控线程
     */
    public void start(){
        monitor = new Thread(()->{
            while (true) {
                Thread current = Thread.currentThread();
                if(current.isInterrupted()) {
                    log.debug(\"料理后事...\");
                    break;// 结束线程
                }
                // 执行监控-如果在正常运行中被中断,中断标记会置为true退出循环
                log.debug(\"执行监控\");
                // 睡眠1s-如果在sleep时被interrupt会在抛出异常后清除中断标记,即恢复为false,导致无法结束线程,因此需要在catch中再次中断
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // 将中断标记置为true
                    current.interrupt();
                }
            }
        });
        monitor.start();
    }

    /**
     * 停止监控线程
     */
    public void stop(){
        monitor.interrupt();
    }

}

再写个测试方法:

@Test
public void testTwoPhaseTermination() throws InterruptedException {
    TwoPhaseTermination t1 = new TwoPhaseTermination();
    t1.start();
    Thread.sleep(4500);
    t1.stop();
}

运行结果:Java线程interrupt方法详解

由运行记录可见,该监控线程这次正好在sleep时被中断了,然后料理线程即将结束的后事,最后线程停止运行。

4.interrupted()方法

interrupted()方法也是用来判断线程是否被打断,与isInterrupted()方法不同的是isInterrupted()判断完后不会清除中断标记,而interrupted()判断完后会清除中断标记。Java线程interrupt方法详解

5.interrupt打断park线程

打断 park 线程, 不会清空打断状态,我们写个代码案例:

public static void main(String[] args) throws InterruptedException {
    testInterruptPark();
}

public static void testInterruptPark() throws InterruptedException {
    Thread t1 = new Thread(()->{
        log.debug(\"park\");
        LockSupport.park();
        log.debug(\"unpark\");
        log.debug(\"中断标志:{}\", Thread.currentThread().isInterrupted());
    },\"t1\");

    t1.start();

    Thread.sleep(1000);
    t1.interrupt();
}

运行结果:Java线程interrupt方法详解

注意:

1)如果不执行t1.interrupt方法,只会打印park,LockSupport.park()让程序阻塞,无法继续运行

2)t1.interrupt执行中断后,中断标记没有被清除,仍然为true,如果后续再次执行LockSupport.park()则不会再阻塞程序,而是直接继续往下运行,也就是park方法失效了,如下:

log.debug(\"park\");
LockSupport.park();
log.debug(\"unpark\");
log.debug(\"中断标志:{}\", Thread.currentThread().isInterrupted());
LockSupport.park();
log.debug(\"park此时无效,继续执行\");

如果想要park继续生效,就要恢复中断标记,而恢复就需要执行interrupted()方法,如下:

log.debug(\"park\");
LockSupport.park();
log.debug(\"unpark\");
log.debug(\"中断标志:{}\", Thread.currentThread().interrupted());
LockSupport.park();
log.debug(\"park此时有效,程序阻塞\");

6. 总结

以上就是Java线程interrupt方法详解的全部内容,希望对你有帮助。欢迎持续关注潘子夜个人博客(www.panziye.com),学习愉快哦!

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/9878.html

管理员

相关推荐
2025-08-06

文章目录 一、Reader 接口概述 1.1 什么是 Reader 接口? 1.2 Reader 与 InputStream 的区别 1.3 …

988
2025-08-06

文章目录 一、事件溯源 (一)核心概念 (二)Kafka与Golang的优势 (三)完整代码实现 二、命令…

465
2025-08-06

文章目录 一、证明GC期间执行native函数的线程仍在运行 二、native线程操作Java对象的影响及处理方…

348
2025-08-06

文章目录 一、事务基础概念 二、MyBatis事务管理机制 (一)JDBC原生事务管理(JdbcTransaction)…

456
2025-08-06

文章目录 一、SnowFlake算法核心原理 二、SnowFlake算法工作流程详解 三、SnowFlake算法的Java代码…

517
2025-08-06

文章目录 一、本地Jar包的加载操作 二、本地Class的加载方法 三、远程Jar包的加载方式 你知道Groo…

832
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号