贾哇技术指南

V1

2022/04/09阅读:20主题:默认主题

如何处理InterruptedException异常

如何处理InterruptedException异常

前言

当你捕捉到InterruptedException异常时,在catch代码块里会如何处理呢?首先我们来看下什么时候会抛出InterruptedException异常。 java.lang.InterruptedException类的注释中有提到:

  • @see java.lang.Object#wait()
  • @see java.lang.Object#wait(long)
  • @see java.lang.Object#wait(long, int)
  • @see java.lang.Thread#sleep(long)
  • @see java.lang.Thread#interrupt()
  • @see java.lang.Thread#interrupted()

此外,由于 java.lang.Thread#join() 底层也是通过java.lang.Object#wait()实现的,所以也可能会抛出此异常。举个栗子:当前线程在调用sleep(long)方法时,另外一个线程调用了该线程的interrupt()方法, 则会抛出此异常。示例代码如下:

public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Hello,World");
            }
        }, "print-thread");
        thread.start();
        thread.interrupt();
    }

运行结果如下:

java.lang.InterruptedException: sleep interrupted
 at java.lang.Thread.sleep(Native Method)
 at com.jts.base.thread.HowToStopThread.lambda$main$0(HowToStopThread.java:13)
 at java.lang.Thread.run(Thread.java:748)
Hello,World
Hello,World
Hello,World
。。。

可以看到这里抛出了java.lang.InterruptedException异常,并且打印线程还在继续打印,并没有中断。 首先我们要明白:Java线程的中断机制是一种协作机制,调用中断方法仅仅只是修改线程对象中是否中断字段的值(有兴趣的小伙伴可以去看hotspot源码,这个字段在osThread.cpp文件中,字段名是:_interrupted)。也就是说通过调用interrupt()中断方法并不能直接终止另一个线程,而是需要被中断的线程自己处理中断请求。所以上面的代码并不能中断打印线程,而是会一直打印下去。

如何处理InterruptedException异常

首先我们看下如何通过线程的中断状态来停止上面的打印线程,首先我们将上面的代码改造成下面这样:

public static void main(String[] args) throws Exception {
        Thread thread = new Thread(() -> {
            // 当线程状态是未中断时才执行打印
            while (!Thread.interrupted()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Hello,World");
            }
        }, "print-thread");
        thread.start();
        Thread.sleep(2000);
        thread.interrupt();
    }

你觉得打印线程会终止吗?


答案是并不会,虽然我们添加了!Thread.interrupted()条件,但是打印线程还在一直打印,这是因为在Java中引发InterruptedException的任何方法在发生异常时都会 将中断标志重置为false,所以我们加的条件并没有生效。如果想要我们的条件生效,就要在catch里面进行处理了,改造后的catch代码块如下:

catch (InterruptedException e) {
                    // 将中断状态置位true
                    Thread.currentThread().interrupt();
                    e.printStackTrace();
                }

这样打印线程就不会再打印了。

总结下,如何处理InterruptedException呢?

  • 如果可以将异常抛出,可以直接抛给调用者。
  • 如果不方便将异常抛出,可以在catch代码块中调用Thread.currentThread().interrupt()方法将线程的中断状态设置为true,以便其他操作可以感知到此线程被中断了。

小结

调用Thread.interrupt()并不会中断该线程,只是会将该线程对象的中断状态设置为true,需要用户自己来决定是否需要根据该状态来判断程序是否应该继续执行。当抛出InterruptedException异常时,会将线程对象的中断状态设置为false,一般有两种方式处理InterruptedException

  1. 将该异常抛出
  2. catch代码块中调用Thread.currentThread().interrupt()方法

ps:《刺客伍六七》的粉丝已经更新了第四季,果然成熟的粉丝都会自己更新了,链接在这: 第四季链接 你懂得。。。

好了,这篇文章就到这里了,感谢大家的观看!如有错误,请及时指正!欢迎大家关注我的公众号:贾哇技术指南

分类:

后端

标签:

后端

作者介绍

贾哇技术指南
V1