线程中断是线程通讯的一种手段,设置线程的中断标识并不意味着该线程会立即挂起,相反,如果该线程对自己的中断标识的变化不采取任何手段,则该中断标识将没有任何意义,程序将继续向下运行。
主要涉及到三个主要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 线程中断标志的正确使用方法
通常在两个场景下线程会被设置中断标志
- 其他线程认为该线程应该终止当前的操作
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()的标准使用方法。
- 打断目标线程的阻塞状态(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();
}
运行结果如下:
2. boolean isInterrupted()
检测当前线程是否被设置中断标志,是则返回true,否则返回false 相比于接下来介绍的interrupted(),该方法更加常用
查看该函数源码发现,其调用的子函数带有一个boolean类型的参数,表示是否清除中断标记。 因此isInterrupted()函数仅仅返回中断标志,不会清除中断标志。
3. interrupted()
查看源码
该函数和isInterrupted()有3点不同
- 该方法为static方法,可以直接利用Thread调用
- 该方法返回的调用该方法的当前线程的终端状态,而不是被调用线程的中断状态
- 该方法的会清除线程的中断标记
下面通过一个例子更好的理解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();
}
输出结果
第一个打印结果是true应该是很容易理解的,因为thread线程被主线程设置了中断标记,因此isinterrupted()为true
第二个打印结果为false可能很多人不理解了,这是因为上文说过的interrupted()这个函数获取的是当前线程的终端状态,因为当前线程是主线程,所以和thread无关(虽然实在thread上调用的该函数)
第三个打印结果同理,由此可见,这里thread.interrupted()和Thread.interrupted()是等价的
第四个打印结果为true,因为isInterrupted()获取的还是thread的中断状态