父线程只能发送一次中断信号?在迭代中有了sleep(),while(!Thread.currentThread().isInterrupted())会失效?
来源:5-5 中断信号

Panda_io
2019-08-17
感谢老师的前面的解惑让我弄清楚了interrupt不是实时被检测而是当遇到阻塞时会触发这个检测(我个人理解为被动检测),“interrupt是一个信号,这个信号并不是实时检测的,也不是每行代码都能检测的,在本例中,只有程序运行到sleep时,才能检测到线程被中断了,然后会抛出异常;而代码在计算其他内容时,比如执行if (num % 100 == 0)时,是无法感知到中断已经发生了的。所以问题不在于休眠时间的长短,而是在于“每次循环都有休眠,所以终究会运行到休眠的sleep代码,在sleep时才会抛出异常”。
但是我后面想主动去检测这个中断,第一种设想我是在父线程不断给子线程发送中断信号,就算第一次处于休眠期间并且清除了中断信号那么没关系,我后面的中断请求总有一个你可以在while(!Thread.currentThread().isInterrupted())接收到吧,然而当我运行代码的时候发现,当第一次抛出异常后程序就卡住了,难道父线程只能像启动线程那样也只能使用一次中断?我查看了下interrupt()源码,首先会检查路径,然后检查blocker是否为空,不为空设置中断标志,最后执行这个 blocker.interrupt(this)再结束方法(这行代码没太懂),如果为空仅设置中断标识然后结束方法。看了几遍发现还是没有头绪,代码如下:
运行结果,运行中抛出第一次中断错误后会卡在那儿,如箭头所示,并未结束。
第二种设想,既然上面不行,那我手动一次一次运行看有没有可能不抛出中断异常直接结束,然而我发现历史总是惊人的相似。
那么问题来了,当迭代中出现slee()时为什么在while(!Thread.currentThread().isInterrupted())检测不到中断,只能在sleep()时候检查到中断信号呀(而且已经把休眠时间设置得足够短了,测试次数也足够多了),还有父线程只能发送一次信号吗?麻烦老师给小菜鸡解释一下,老师时间宝贵,我也试着自己去寻找答案,实现想不通才求助于您,救救孩子吧。
2回答
-
同学你自己探索、寻找答案的精神值得鼓励,我看了你的问题,也写了代码,解答如下:
结论:
第一,父线程并不是只能发送一次信号,你第一个代码里的
while (true) { thread.interrupt(); }
那么确实就是会一直给子线程发送中断信号,不止一次。
第二,迭代中出现slee()时为什么在while(!Thread.currentThread().isInterrupted())检测不到中断,只能在sleep()时候检查到中断信号?
实际上并不是while(!Thread.currentThread().isInterrupted())检测不到中断,而是你的for循环里什么都没写,代码自动优化把你的for循环忽略了,所以相当于你的Runnable里面的while循环就只做了一件事:Thread.sleep(1),这样一来,自然在被中断时候一定是在sleep的,因为它没有做别的事。
第三,图片里为什么程序不停止?
这并不是子线程不停止,其实子线程已经被中断并且停止了,但是由于主线程的代码
while (true) { thread.interrupt(); }
是无限循环,所以整个程序不会停止。
第四,我写了代码验证了你的问题,验证结果是while(!Thread.currentThread().isInterrupted())完全是可以检测到中断发生的,并不是一定要在sleep里才能检测到的,代码如下:
public static void main(String[] args) throws InterruptedException { Runnable runnable = () -> { while (!Thread.currentThread().isInterrupted()) { for (int i = 0; i < 100; i++) { System.out.print("1"); } System.out.println(); try { Thread.sleep(1); } catch (InterruptedException e) { System.out.println("未在while处中断"); } for (int i = 0; i < 100; i++) { System.out.print("2"); } System.out.println(); } }; Thread thread = new Thread(runnable); thread.start(); Thread.sleep(1000); while (true) { thread.interrupt(); } }
根据每个电脑的CPU不同,你把Thread.sleep(1000)里面的时间可以做调整,然后多次运行,会发现有的时候是停止在了sleep期间,所以会打印"未在while处中断":
而有的时候,会停止在while(!Thread.currentThread().isInterrupted())期间,所以不会打印“未在while处中断”:
希望解答了你的困惑~
992020-05-15 -
黑子的一生
2019-09-11
老师真的好啊!真的好负责!么么哒
112019-09-14
相似问题