中断机制与API实现
😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 博客首页 @怒放吧德德 To记录领地
🌝分享学习心得,欢迎指正,大家一起学习成长!
转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人
文章目录
前言
在Java中,线程中断是一种机制,用于通知线程应该停止当前正在执行的任务。中断通常用于协同线程之间的合作,以便让线程在适当的时候终止其工作,尤其是在长时间运行的任务或阻塞操作中。通过学了多线程以及synchronized的相关知识,接下来就到了学习线程中断知识。
中断机制
在Java中,中断机制的概念被引入到多线程编程中,用于线程间的协作和通信。线程的中断机制使得线程可以在不中止其执行的情况下,通过发送中断信号来通知线程应该停止当前的工作或改变其执行流程。
尽管在Java中Thread.stop()、Thread.suspend() 和 Thread.resume()三个API,但是线程的中断/停止应该是由线程本身来停止,所以这些也已经被废弃了。
而且Java中没有办法来立即停止一条线程,但是又需要停止线程,Java提供了一种协商机制:中断。
三大中断方法
在Java中,线程中断(Thread Interruption)是一种用于请求线程停止其当前任务或改变执行状态的机制。它不是强制性的终止,而是通过设置一个“中断标志”来提示目标线程可以停止执行,具体需要目标线程自行检查该标志并作出响应。Java也提供了许多API,但其中有三个中断方法是主要的。
这三个API分别是 interrupt()
、isInterrupted()
和 interrupted()
,接下来我们也将仔细学习这三个主要的API。
interrupt
具体API - 实例方法 - public void interrupt()
请求线程中断,仅仅只是将线程的中断标志设置为true
,发起一个协商但并不是立即停止线程。
使用场景:常用于从外部中断线程,提示该线程可以停止当前工作。
Thread thread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 执行任务
}
});
thread.start();
thread.interrupt(); // 请求中断该线程
interrupted
具体API - 静态方法 - public static boolean interrupted()
静态方法,检查当前线程的中断状态,并清除中断标志。第二次调用该方法会返回 false,因为中断标志已经被清除。
这里需要注意的是:
- 如果线程在wait(),wait(long)调用阻塞,或wait(long, int) Object类的方法,或者对join(),join(long),join(long, int),sleep(long),或sleep(long, int),这类方法,那么它的中断状态将被清除,它会收到InterruptedException异常。
- 如果该线程被阻塞在I/O操作在一个InterruptibleChannel然后通道将被关闭,该线程的中断状态将被设置,并且线程将获得ClosedByInterruptException。
- 如果该线程是在一个Selector然后该线程的中断状态将被设置,它会立即从选择操作回流受阻,可能是一个非零的值,就像选择器的wakeup方法调用。
- 如果前面的条件没有保持,那么这个线程的中断状态将被设置。
- 中断一个不活跃的线程不会有任何效果。
换句话说,如果这个方法被连续调用两次,那么第二个调用将返回false(除非当前线程再次中断,在第一个调用已经清除其中断状态之后,在第二个调用之前已经检查过)。 忽略线程中断,因为线程在中断时不存在将被该方法返回false所反映。
使用场景:当需要检查并同时重置中断状态时使用。
if (Thread.interrupted()) {
// 处理中断情况,并且清除中断状态
}
isInterrupted
具体API - 实例方法 - public boolean isInterrupted()
检查当前线程是否被中断。返回 true 表示线程已经被请求中断,但不会清除中断状态。
使用场景:一般是用来定期检查线程的中断标志,以决定是否需要提前结束任务。
if (Thread.currentThread().isInterrupted()) {
// 线程已经被请求中断,做一些清理或退出操作
}
通过以下简单的demo来了解一下以上的API
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread taskThread = new Thread(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("任务执行中...");
Thread.sleep(2000); // 模拟长时间操作
}
} catch (InterruptedException e) {
System.out.println("线程被中断!");
}
});
taskThread.start();
Thread.sleep(5000); // 主线程等待5秒后中断任务线程
taskThread.interrupt(); // 请求中断
}
}
通过运行,我们可以看到,在线程启动后,如果没有检测到请求中断,那么就会一直执行,直到请求中断,JVM会将中断标记位设置为true,此时检测到就会执行中断业务。
Java线程中断机制是通过设置和检查中断标志来实现的,线程本身需要定期检查标志来响应中断请求,而不是直接被强制终止。通过API interrupt()、isInterrupted() 和 interrupted(),我们可以灵活地管理线程的中断行为。
中断线程的实现
如何来停止中断运行中的线程?其实也有许多方法,只要能够提供一个具有可见性的变量,就能够做到中断线程,因为我们上文提到了,中断线程应该是由线程自己来中断,我们可以通过判断某个值是否达到标记的值,是的话就执行中断,当然也可以使用中断的API,道理都是差不多的。接下来就来看看例子。
volatile实现
关于volatile可以看一下之前的文章《【多线程与高并发】- 浅谈volatile》。这篇文章对volatile做了详细讲解,这里我们就需要清楚一点是volatile的一个可见性的特性,当我们某个线程对加了此修饰的变量修改了,其他线程是能够感知的到的。
我们通过一个例子来解释,首先定义一个用volatile
修饰的变量,其次在执行线程t1的时候,会进入一段循环,来实现线程t1在不断地执行,如果flag被修改为true,则退出循环,此线程也就停止。接着通过睡眠10毫秒,启动另一个线程t2来进行修改flag。
/**
* 中断demo
* @Author: lyd
* @Date: