线程中断是线程通讯的一种手段,设置线程的中断标识并不意味着该线程会立即挂起,相反,如果该线程对自己的中断标识的变化不采取任何手段,则该中断标识将没有任何意义,程序将继续向下运行。

主要涉及到三个主要API。

1. interrupt()

1.1 测试中断之后线程是否会继续执行

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

Thread thread = new Thread(() -> {
for (; ; ) {
System.out.println(Thread.currentThread().getName() + " is saying hello");
}
});

//启动thread线程
thread.start();

//main线程首先等待1S,目的是让thread线程首先启动
Thread.sleep(1000);

//设置中断标识
thread.interrupt();
}


运行结果:程序会不断进行打印,并不会终止


1.2 线程中断标志的正确使用方法

通常在两个场景下线程会被设置中断标志

  1. 其他线程认为该线程应该终止当前的操作
public static void main(String[] args) throws InterruptedException {

Thread thread = new Thread(() -> {
//如果当前线程没有被设置中断标志,则该线程继续运行
while (!Thread.currentThread().isInterrupted()) {
System.out.println(Thread.currentThread().getName() + " is go on working");
}
});

//启动thread线程
thread.start();

//main线程首先等待1S,目的是让thread线程首先启动
Thread.sleep(1000);

//设置中断标识
thread.interrupt();
}


运行结果:1S之后程序会停止


该程序和上一段程序的唯一区别就在于for循环变成了while循环,并且在while循环中不断地检查当前线程是否被设置中断标志,这也是isInterrupted()的标准使用方法。

  1. 打断目标线程的阻塞状态(wait,join,sleep导致),强制抛出异常并返回
public static void main() throws InterruptedException {
Thread thread = new Thread(() -> {
try {
System.out.println("线程即将进入睡眠...");
Thread.sleep(1000000);
System.out.println("线程被唤醒...");
} catch (InterruptedException e) {
System.out.println("线程睡眠过程中被打断");
//使该线程继续向下运行
}
System.out.println("其他业务被执行");
});

//启动thread线程
thread.start();

//main线程首先等待1S,目的是让thread线程首先启动
Thread.sleep(1000);

//打断子线程sleep状态,抛出异常强行退出
thread.interrupt();

}

运行结果如下:

线程中断之-interrupt()、isInterrupted()、interrupted()_Java

2. boolean isInterrupted()

检测当前线程是否被设置中断标志,是则返回true,否则返回false 相比于接下来介绍的interrupted(),该方法更加常用

线程中断之-interrupt()、isInterrupted()、interrupted()_抛出异常_02

查看该函数源码发现,其调用的子函数带有一个boolean类型的参数,表示是否清除中断标记。 因此isInterrupted()函数仅仅返回中断标志,不会清除中断标志。

3. interrupted()

查看源码

线程中断之-interrupt()、isInterrupted()、interrupted()_后端_03

该函数和isInterrupted()有3点不同

  1. 该方法为static方法,可以直接利用Thread调用
  2. 该方法返回的调用该方法的当前线程的终端状态,而不是被调用线程的中断状态
  3. 该方法的会清除线程的中断标记

下面通过一个例子更好的理解isInterrupted()和interrupted()之间的区别(例子摘取自《并发编程之美》)

public static void compare() throws InterruptedException {
Thread thread = new Thread(() -> {
for (; ; ) {

}
});

//启动线程
thread.start();

//设置中断标志
thread.interrupt();

//1.获取中断标志
System.out.println("isInterrupted:" + thread.isInterrupted());

//2.获取中断标志并重置
System.out.println("interrupted:" + thread.interrupted());

//3.获取中断标志并重置
System.out.println("interrupted:" + Thread.interrupted());

//4.获取中断标志
System.out.println("isInterrupted:" + thread.isInterrupted());

thread.join();

}

输出结果

线程中断之-interrupt()、isInterrupted()、interrupted()_重置_04


第一个打印结果是true应该是很容易理解的,因为thread线程被主线程设置了中断标记,因此isinterrupted()为true




第二个打印结果为false可能很多人不理解了,这是因为上文说过的interrupted()这个函数获取的是当前线程的终端状态,因为当前线程是主线程,所以和thread无关(虽然实在thread上调用的该函数)




第三个打印结果同理,由此可见,这里thread.interrupted()和Thread.interrupted()是等价的




第四个打印结果为true,因为isInterrupted()获取的还是thread的中断状态