请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

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

感谢老师的前面的解惑让我弄清楚了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回答

悟空 2019-08-17 18:12:12

同学你自己探索、寻找答案的精神值得鼓励,我看了你的问题,也写了代码,解答如下:

结论:

第一,父线程并不是只能发送一次信号,你第一个代码里的

while (true) {
    thread.interrupt();
}

那么确实就是会一直给子线程发送中断信号,不止一次。


第二,迭代中出现slee()时为什么在while(!Thread.currentThread().isInterrupted())检测不到中断,只能在sleep()时候检查到中断信号?

实际上并不是while(!Thread.currentThread().isInterrupted())检测不到中断,而是你的for循环里什么都没写,代码自动优化把你的for循环忽略了,所以相当于你的Runnable里面的while循环就只做了一件事:Thread.sleep(1),这样一来,自然在被中断时候一定是在sleep的,因为它没有做别的事。


第三,图片里为什么程序不停止?

https://img1.sycdn.imooc.com//szimg/5d57d1e8094ee76911340644.jpg

这并不是子线程不停止,其实子线程已经被中断并且停止了,但是由于主线程的代码

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处中断":

https://img1.sycdn.imooc.com//szimg/5d57d2ba090461eb18400764.jpg

而有的时候,会停止在while(!Thread.currentThread().isInterrupted())期间,所以不会打印“未在while处中断”:

https://img1.sycdn.imooc.com//szimg/5d57d2dd090f503d18300740.jpg


希望解答了你的困惑~

9 回复 有任何疑惑可以回复我~
  • 老师你太认真负责了,太牛逼了,敬佩
    回复 有任何疑惑可以回复我~ 2019-08-17 18:14:30
  • 提问者 Panda_io #2
    真的非常感谢老师,老师真的非常认真负责,看了您的解答我恍然大悟,还是自己思考的时候不够仔细,没有注意到一些细节,下次提问题一定反复深思熟虑之后再提。在慕课网学习四年了,第一次遇到能给我一种高中老师给同学解答问题的感觉(超级热心耐心以及仔细),让我再回味了一次高中的生活哈哈。在本科的技术学得太菜了,没有去找工作,选择考研好好把技术学好,没想到能遇到这么好的老师,简直不要太幸运!!!
    回复 有任何疑惑可以回复我~ 2019-08-17 19:31:13
  • 提问者 Panda_io #3
    非常感谢!
    回复 有任何疑惑可以回复我~ 2019-08-17 19:37:30
黑子的一生 2019-09-11 11:56:45

老师真的好啊!真的好负责!么么哒

1 回复 有任何疑惑可以回复我~
  • 提问者 Panda_io #1
    那确实是个超级好的老师!
    回复 有任何疑惑可以回复我~ 2019-09-14 10:02:29
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信