java - Java线程InterruptExceptioon处理仅在某些情况下阻止了进一步的代码执行

标签 java multithreading java-11

以下简短的示例代码说明了我无法解释的行为

    ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
    
    Thread t = new Thread(() -> {
        long cnt = 0;
        try {
            while(!Thread.currentThread().isInterrupted()) {
                testQueue.add(Math.random());
                cnt++;
                try {
                    Thread.sleep(100);
                }catch (Exception e) {
                    System.out.println(String.format("inner interrupted inserted %d record", cnt));
                }
            }
        } catch (Exception e) {
            System.out.println(String.format("interrupted inserted %d record", cnt));
        }
        System.out.println(String.format("inserted %d record", cnt));
    });
如果我调用t.interrupt()来中断线程
预期的行为是2条显示以下内容的行:
inner interrupted inserted %d record
inserted %d record
其中%d被替换为相应的值。
但实际结果是
inner interrupted inserted %d record
如果我们将内部捕获移除到线程
    ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
    
    Thread t = new Thread(() -> {
        long cnt = 0;
        try {
            while(!Thread.currentThread().isInterrupted()) {
                testQueue.add(Math.random());
                cnt++;
                Thread.sleep(100);
            }
        } catch (Exception e) {
            System.out.println(String.format("interrupted inserted %d record", cnt));
        }
        System.out.println(String.format("inserted %d record", cnt));
    });
然后我们得到输出
interrupted inserted %d record
inserted %d record
正如预期的那样,现在外部捕获正在捕获InterruptException
但是,如果我改为在第一个代码示例的最内层捕获中放置中断,如下所示:
    ConcurrentLinkedDeque<Double> testQueue = new ConcurrentLinkedDeque<>();
    
    Thread t = new Thread(() -> {
        long cnt = 0;
        try {
            while(!Thread.currentThread().isInterrupted()) {
                testQueue.add(Math.random());
                cnt++;
                try {
                    Thread.sleep(100);
                }catch (Exception e) {
                    System.out.println(String.format("inner interrupted inserted %d record", cnt));
                    break; //this one
                }
            }
        } catch (Exception e) {
            System.out.println(String.format("interrupted inserted %d record", cnt));
        }
        System.out.println(String.format("inserted %d record", cnt));
    });
产生了预期的行为。
挡块的位置为什么会产生这种差异?

最佳答案

请参阅 Thread#interrupt 的文档:

If this thread is blocked in an invocation of [...] sleep(long), or sleep(long, int), [...], then its interrupt status will be cleared and it will receive an InterruptedException.


If none of the previous conditions hold then this thread's interrupt status will be set.


这意味着在您的示例中,Thread#sleep均会抛出异常XOR Thread.currentThread().isInterrupted()给您true。
因此,在第一个示例中,您捕获到异常,执行打印并在无限循环中输入/停留,因为Thread.currentThread().isInterrupted()始终为false
在您的第二个示例中,try-catch没有嵌套在循环内,因此两次打印均会发生,并且线程将按预期终止。
在第三个示例中,您只是明确退出了循环。

仅供引用:您无需编写System.out.println(String.format(...))。有System.out.printf,但请不要忘记\n

关于java - Java线程InterruptExceptioon处理仅在某些情况下阻止了进一步的代码执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64921763/

相关文章:

java - NullPointerException,在尝试使用 facebook graph api 从 JSON 对象检索值时?

java - 为什么我必须抛出这个语句才能得到结果?

C++ 等价于 Java 的 BlockingQueue

java - 由于Thread.currentThread().run()而递归调用run方法

java - 集群环境下Spring Security并发 session 控制max-session

java - Jython - 使用 Python 数据结构或 Java 数据结构更快吗?

c - 使用 GDB 单步调试多线程应用程序

java - 如何在Fabric8 Open Jdk Container中启用扩展编码?

java - 如何解决java.lang.NoClassDefFoundError : javax/xml/bind/JAXBException