前言
在学lock底层原理的时候,碰到了线程中断方面的知识点,然后平时在学习多线程的时候,也接触到了中断的知识点,但一直以来都是一知半解的,所以今天就来总结学习一波
首先来说一下总结:
在java中,线程的中断(interrupt)只是改变了线程的中断状态,注意:只是改变了线程的中断状态!至于这个中断状态改变后带来的结果,那是无法确定的,有时它更是让停止中的线程继续执行的唯一手段。不但不是让线程停止运行,反而是继续执行线程的手段。
思考如何安全的关闭线程
早期的时候,Thread类中有一个stop方法,用于强行关闭一个线程。但是后来发现此操作并不安全,强行关闭可能导致一致性问题。故stop方法已被官方弃用。
这个时候就可以换一种思路来想一下,线程中断的本质就是想让正在运行的线程结束,而我们知道,只要线程的run方法"完成",底层操作系统的线程就会被释放。"完成"就意味着run方法结束,而结束的方式有两种,一种是抛出异常,另一种则是方法返回。所以,我们要做的就是控制线程任务,抛出异常或返回(return)。
中断机制
强制结束线程被取消,取而代之的,是一种协作机制,即中断机制。也就是说,一个线程只能向另一个线程发送中断信号,而不能强行对其进行关闭。而另一个线程如何处理,就得看其正在执行的代码对中断信号如何反应了
我们可以使用Thread.currentThread()静态方法将获得当前执行此段代码的线程对象。然后调用interrupted()方法获取线程中断状态,如果线程被中断,则返回true。线程的中断状态可以用interrupt()方法设置。
下面提一下中断可能产生让人产生疑惑的几个方法:
- interrupt() => 设置中断状态,设置为已中断
- isInterrupted() => 获取中断状态
- interrupted() => 恢复中断状态,并返回恢复前的状态。(即如果被中断,会设置为未中断,并返回true)
为什么sleep会抛出异常
在说中断之前,先说一下sleep,在多线程中sleep相信大家都有使用过吧,就是让线程休眠指定毫秒,但是使用sleep的时候为什么捕获异常呢?
在此处,如果不捕获异常,idea会直接报错的
使用sleep后,线程会等待三秒后执行,那假如对线程使用了中断方法的话是什么情况呢?
可以看到,thread线程执行sleep方法后进入睡眠,但是在main方法执行 thread.interrupt() 方法后,休眠的线程立抛出了 InterruptedException 异常,之所以会抛出这个异常:主要的目的是让休眠的线程提前醒来
举一个例子来说明这个情况,假如有个车道,每一次只能通过一辆车,现在A车先通过,然后B车在等待,等A车通过之后,B车才能从等待状态变成运行状态,那想一下,B车要等待多久才合适呢?等久了浪费时间,等短了的话,A车还没开过去,那这个时候,中断就能很好解决这个问题。
思考(这个是重点,明白了以下三个问题,才真正明白”中断“)
线程在sleep的时候,是什么状态
超时等待状态(TIMED_WAITING),等睡眠时间过了之后进入RUNNABLE状态
什么时候会抛出 InterruptedException
我们可以在java代码中找到 InterruptedException 这个类,上面有一句话
有这样的一句话:当线程处于等待、睡眠或其他占用状态,并且线程在活动之前或活动期间被中断时抛出。
当线程处于 "等待、睡眠" 那就说明:如果线程在sleep或者wait期间调用中断方法就肯定会抛出异常,那 “线程在活动之前或活动期间” 说的是不处于运行(RUNNABLE)状态的线程执行了中断方法就会抛出异常
如果线程没有睡眠,调用它的 interrupt 方法会怎样?
现在我们知道了不是处于运行状态的线程执行了中断方法就会抛出异常 ,那如果当前线程是正常运行,并且调用了interrupt 方法呢?
其实触发 InterruptedException 异常 只是"中断"在线程非活跃状态下的表现形式,"中断"的本身跟线程是否在活跃状态是没有关系的。
之所以在不活跃状态下中断会抛出异常,是为了让你知道线程回到运行状态的原因,让你知道它是睡到自然醒了呢,还是被谁打断了呢,回到运行状态让你处理被中断之后的代码逻辑,就跟我上面举的例子一样,B车被中断睡眠之后,回到运行状态才能决定是往前开还是退出车道,这个完全取决于B车自己的选择。
整理下思路,确定上面的东西都能听懂之后再继续。
那如果线程的状态本来就是活跃的,这个时候触发中断,线程会假装看不见并且继续做他该做的事儿,那活跃状态的线程不就相当于把中断给无视掉了??那这个就要看你的需求了,如果你不想处理中断的话,那就真的无视掉了。
但是如果你想要处理中断的话,那也是可以处理的,想要处理中断的前提是知道自己被中断了,那一个线程在运行状态下如何知道自己被中断了呢??那要使用到以下的两个方法
- isInterrupted() => 获取中断状态
- interrupted() => 恢复中断状态,并返回恢复前的状态。(即如果被中断,会设置为未中断,并返回true)
以上内容是我看b站了的视频,以及网上的博客还有我本身的理解整理出来,如果有帮助,希望点个👍
b站视频地址(强烈推荐,多看几次对中断的理解能有很大的帮助):【Java并发·08】线程中断 interrupt_哔哩哔哩_bilibili