一文了解JAVA线程的中断(Interrupt)机制

简介: 一文了解JAVA线程的中断(Interrupt)机制

介绍


Java的中断是一种协作机制,也就是说通过中断并不能直接中断另外一个线程,而需要被中断的线程自己处理中断。

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


中断方法


线程中断相关的方法主要是下面的3方法,他们具体的作用见下面的表格:

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

记忆方法推荐:

  • interrupt()是一个动词,表示中断线程。
  • Interrupted是一个形容词,用于检查线程的中断位,而isInterrupted()方法只是简单的检查,interrupted()处理的更加复杂。


可中断的阻塞


针对线程处于由sleep, wait, joinLockSupport.park等方法调用产生的阻塞状态时,调用interrupt方法,会抛出异常InterruptedException,同时会清除中断标记位,自动改为false。


不可中断的阻塞


  1. java.io包中的同步Socket I/O
  2. java.io包中的同步I/O
  3. Selector的异步I/O
  4. sychronized加的锁


实践案例


中断sleep、wait、join等方法


private static void test1() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error("error", e);
            }
        }, "t1");
        t1.start();
        Thread.sleep(500);
        t1.interrupt();
        Thread.sleep(100);
        log.info(" interrupt status : {}", t1.isInterrupted());
}

1671089657989.jpg

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


中断LockSupport.park方法


public static void test3() throws InterruptedException {
        Thread t3 = new Thread(() -> {
            log.debug("t3 park.....");
            LockSupport.park();
            log.debug("t3 unpark.....");
            log.debug("interrupt status: [{}]", Thread.currentThread().isInterrupted());
            log.debug("t3 第二次 park.....");
            LockSupport.park();
            log.debug("t3 中断位为true, park失效.....");
        }, "t3");
        t3.start();
        Thread.sleep(1000);
        t3.interrupt();
    }

1671089680990.jpg

结论: 阻塞方法park响应中断, 不会抛出异常,同时不会清除中断标记位,任为true。


中断正常方法


private static void test2() throws InterruptedException {
        Thread t2 = new Thread(() -> {
            while (true) {
                boolean isInterrupted = Thread.currentThread().isInterrupted();
                if (isInterrupted) {
                    log.info("interrupt status: {}", isInterrupted);
                    break;
                }
            }
        }, "t2");
        t2.start();
        Thread.sleep(500);
        t2.interrupt();
        Thread.sleep(100);
        log.info(" thread status, {}, interrupt status : {}", t2.getState(), t2.isInterrupted());
    }

1671089694506.jpg

结论: 打断正常运行的线程, 不会清空打断状态,同时线程结束后,重置中断状态位。


常见模式


这里提供针对interrupt中断使用的一种常见模式,方便大家在后续的开发过程中使用。


两阶段中止模式


使用场景


在一个线程中“优雅”地停止另一个线程的工作,在停止的时候给另一个线程"料理后事"的机会。比如有个监控线程在做监控,在主线程可以终止他的工作。


代码展示

class MonitorTask {
    private Thread thread;
    // 开始监控
    public void start() {
        thread = new Thread(() -> {
           while (true) {
               Thread curr = thread.currentThread();
               // 如果当前线程是中断状态
               if(curr.isInterrupted()) {
                   log.debug("清理资源,料理后事");
                   break;
               }
               try {
                   // 监控执行工作...
                   log.debug("监控执行ing");
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   log.error("error", e);
                   // 此处中断位被清除,变为false, 重新改为true,进入循环,处理线程后事
                   curr.interrupt();
               }
           }
        }, "监控线程");
        thread.start();
    }
    // 终止线程
    public void stop() {
        thread.interrupt();
    }
}
MonitorTask monitorTask = new MonitorTask();
monitorTask.start();
Thread.sleep(1500);
monitorTask.stop();

1671089722696.jpg

目录
相关文章
|
3月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
236 1
|
3月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
250 1
|
4月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
Java 数据库 Spring
209 0
|
4月前
|
算法 Java
Java多线程编程:实现线程间数据共享机制
以上就是Java中几种主要处理多线程序列化资源以及协调各自独立运行但需相互配合以完成任务threads 的技术手段与策略。正确应用上述技术将大大增强你程序稳定性与效率同时也降低bug出现率因此深刻理解每项技术背后理论至关重要.
379 16
|
5月前
|
缓存 并行计算 安全
关于Java多线程详解
本文深入讲解Java多线程编程,涵盖基础概念、线程创建与管理、同步机制、并发工具类、线程池、线程安全集合、实战案例及常见问题解决方案,助你掌握高性能并发编程技巧,应对多线程开发中的挑战。
|
5月前
|
数据采集 存储 前端开发
Java爬虫性能优化:多线程抓取JSP动态数据实践
Java爬虫性能优化:多线程抓取JSP动态数据实践
|
6月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
392 83
|
6月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
311 0
|
6月前
|
人工智能 前端开发 安全
Java开发不可不知的秘密:类加载器实现机制
类加载器是Java中负责动态加载类到JVM的组件,理解其工作原理对开发复杂应用至关重要。本文详解类加载过程、双亲委派模型及常见类加载器,并介绍自定义类加载器的实现与应用场景。
295 4