interrupted、interrupt、isInterrupted 三者关系全解析

interrupted、interrupt、isInterrupted 三者关系全解析

在 Java 线程中断机制中,interrupt()interrupted()isInterrupted() 是核心且极易混淆的三个方法,它们围绕线程中断标志位工作,但职责、行为、调用方式完全不同。下面从「核心概念→方法拆解→对比→实战场景」层层讲透。

一、先理解核心:线程中断标志位

Java 中的“中断”不是强制终止线程,而是给线程设置一个布尔类型的中断标志位(线程内部的一个状态):

  • 线程本身可以感知这个标志位,决定是否停止执行(是“协作式”而非“强制式”);
  • 当线程处于 sleep()wait()join() 等阻塞状态时,若被中断,会抛出 InterruptedException,并清除中断标志位(标志位变回 false);
  • 三个方法的核心区别,本质是对这个标志位的「设置」「查询」「查询并清除」的不同操作。

二、逐个拆解三个方法

1. interrupt():设置中断标志位(核心动作)

核心定义

public void interrupt()
属于 Thread 类的实例方法,作用是给目标线程设置中断标志位为 true(仅设置标志,不直接终止线程)。

关键特性

  • 调用方式:通过线程对象调用(如 thread.interrupt()),作用于该线程;
  • 特殊场景:若目标线程正处于阻塞状态(sleep/wait/join),会立即抛出 InterruptedException,并清除中断标志位(标志位变回 false);
  • 无返回值:仅执行“设置标志”动作,不返回任何结果。

示例代码

public class InterruptDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            // 循环检测中断标志位
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("线程运行中...");
                try {
                    Thread.sleep(500); // 阻塞状态
                } catch (InterruptedException e) {
                    System.out.println("捕获到中断异常,此时标志位:" + Thread.currentThread().isInterrupted());
                    // 若想让线程退出,需手动再次设置中断标志(因为异常会清除标志)
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println("线程退出,最终标志位:" + Thread.currentThread().isInterrupted());
        });

        t1.start();
        Thread.sleep(2000); // 主线程等待2秒
        t1.interrupt(); // 给t1设置中断标志
    }
}

输出结果

线程运行中...
线程运行中...
线程运行中...
捕获到中断异常,此时标志位:false
线程退出,最终标志位:true

2. isInterrupted():查询中断标志位(不清除)

核心定义

public boolean isInterrupted()
属于 Thread 类的实例方法,作用是查询目标线程的中断标志位状态不会修改标志位

关键特性

  • 调用方式:通过线程对象调用(如 thread.isInterrupted());
  • 返回值true(已中断)/ false(未中断);
  • 核心区别:仅查询,不改变标志位状态(这是和 interrupted() 的核心差异)。

示例代码

public class IsInterruptedDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            int i = 0;
            while (i < 5) {
                System.out.println("t1运行中,标志位:" + Thread.currentThread().isInterrupted());
                i++;
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        t1.start();
        // 主线程1秒后给t1设置中断
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t1.interrupt();
    }
}

输出结果(关键看标志位变化):

t1运行中,标志位:false
t1运行中,标志位:false
t1运行中,标志位:true  // 中断后标志位变为true
t1运行中,标志位:true
t1运行中,标志位:true

3. interrupted():查询并清除中断标志位(静态方法)

核心定义

public static boolean Thread.interrupted()
属于 Thread 类的静态方法,作用是:

  1. 查询当前线程的中断标志位状态;
  2. 立即清除中断标志位(将标志位重置为 false)。

关键特性

  • 调用方式Thread.interrupted()(静态方法,作用于当前线程);
  • 返回值:返回清除前的标志位状态(true 表示之前是中断状态,false 表示不是);
  • 核心坑点
    • 仅作用于当前线程(调用该方法的线程),而非目标线程;
    • 执行后一定会清除标志位(即使之前是 true,执行后变为 false)。

示例代码

public class InterruptedDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            // 给当前线程设置中断标志
            Thread.currentThread().interrupt();
            
            // 第一次调用:查询并清除标志位(返回true,清除后变为false)
            System.out.println("第一次interrupted():" + Thread.interrupted());
            // 第二次调用:标志位已被清除,返回false
            System.out.println("第二次interrupted():" + Thread.interrupted());
            // isInterrupted()仅查询,此时标志位是false
            System.out.println("isInterrupted():" + Thread.currentThread().isInterrupted());
        });

        t1.start();
    }
}

输出结果

第一次interrupted():true
第二次interrupted():false
isInterrupted():false

三、三者核心对比表

方法名 类型 核心作用 是否清除中断标志 作用对象 返回值
interrupt() 实例方法 设置中断标志位为true 否(阻塞时会清) 目标线程
isInterrupted() 实例方法 查询中断标志位状态 目标线程 boolean
interrupted() 静态方法 查询并清除当前线程的中断标志位 当前线程 boolean

四、实战场景:正确使用中断机制

场景1:优雅停止线程(推荐方式)

public class StopThreadGracefully {
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            // 循环检测中断标志
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("执行任务中...");
                try {
                    Thread.sleep(1000); // 模拟任务耗时
                } catch (InterruptedException e) {
                    System.out.println("任务被中断,准备退出");
                    // 重新设置中断标志(因为sleep抛出异常会清除标志)
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println("线程已优雅退出");
        });

        worker.start();
        Thread.sleep(3000); // 主线程等待3秒
        worker.interrupt(); // 触发中断
    }
}

场景2:避免误用 interrupted()

// 错误示例:用interrupted()查询其他线程的状态(无效,因为它只作用于当前线程)
Thread t1 = new Thread(() -> {});
t1.interrupt();
System.out.println(Thread.interrupted()); // false(作用于主线程,而非t1)
System.out.println(t1.isInterrupted());   // true(正确查询t1的状态)

总结

  1. 核心本质:三者围绕「线程中断标志位」工作,interrupt() 是“设置标志”,isInterrupted() 是“只读查询”,interrupted() 是“查询并清空”;
  2. 关键差异interrupted() 是静态方法(作用于当前线程)且会清除标志位,isInterrupted() 是实例方法(作用于目标线程)且仅查询;
  3. 阻塞场景sleep/wait/join 等阻塞方法被中断时,会抛出 InterruptedException 并清除标志位,需手动重新设置标志位才能让线程感知中断。
posted @ 2026-03-06 22:16  七星6609  阅读(4)  评论(0)    收藏  举报