java自学之路—被中断异常终止线程

178 阅读3分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战

Hope is a good thing, maybe the best of things. And no good thing ever dies—— 《The Shawshank Redemption》

前言

Java 本身的概念还是比较多的,所以学习的开始还是要先打好基础,从一些基本的概念入手,这些都是Java的一些常识。在Java的面试中都是很重要的东西。

上一篇内容我们学习了几种线程的终止方式,今天就来聊一聊一种很常见的中断方式:被中断异常(Interrupt Exception

什么是被中断异常?

我们先查看一下 interrupt() 方法的源码,在其源码的注释中的第二段是这样解释的:

* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.

从上面的注释我们可以看到,当我们的主线程调用 interrupt() 方法去终止线程的时候,如果子线程被 wait()join()或者sleep(long)阻塞的时候,它的中断状态将会被清空,同时还可以得到一个 InterruptedException,此时我们的中断状态就被重置为false。看到这里,我们可以想一下,既然它可以跑出异常,那么我们就可以在它的异常中去中断它的程序。

被中断异常的常见方式

上面我们提到了, 当此方法尝试中断一个处于阻塞状态的线程时,该线程会抛出一个异常 InterruptedException,并将此线程的中断状态,清除为false。所以当子线程处于阻塞状态的时候,我们又想程序能够继续响应它的中断状态,那么我们可以在 catch 中重新中断程序即可。

阻塞状态的代码如下:

package stop;

public class InterruptThread {
    public static void main(String[] args) {
        Runnable runnableThreadImp = () -> {
            Thread currentThread = Thread.currentThread();
            while (!currentThread.isInterrupted()) {
            // 清楚当前线程的中断状态为false,以便响应其它的情况
//            while (!Thread.interrupted() /* && 其它条件 */) {
//                System.out.print("Runnable-Thread" + "\n");
                System.out.println("Runnable-Thread");
                // TODO 清理工作
                try {
                   /***** 此处阻塞子程序 *****/
                    Thread.sleep(200); // 让子线程休眠200毫秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread runnable = new Thread(runnableThreadImp);
        runnable.start();

        try {
            Thread.sleep(5); // 让主线程休眠20ms
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        // 请求中断线程,即设置当前线程的中断状态为true
        // 当此方法尝试中断一个处于阻塞状态的线程时,该线程会抛出一个异常 InterruptedException
        // 并将此线程的中断状态,清除为false
        runnable.interrupt();
    }
}

image.png

从上图可以看出,程序会抛出一个java.lang.InterruptedException: sleep interrupted 的异常。

我们在得到异常的时候再去重新调用 interrupt() 方法去中断程序。

package stop;

public class InterruptThread {
    public static void main(String[] args) {
        Runnable runnableThreadImp = () -> {
            Thread currentThread = Thread.currentThread();
            while (!currentThread.isInterrupted()) {
            // 清楚当前线程的中断状态为false,以便响应其它的情况
//            while (!Thread.interrupted() /* && 其它条件 */) {
//                System.out.print("Runnable-Thread" + "\n");
                System.out.println("Runnable-Thread");
                // TODO 清理工作
                try {
                    Thread.sleep(200); // 让子线程休眠200毫秒
                } catch (InterruptedException e) {
//                    e.printStackTrace();
                   /**** 调用 interrupt() 方法去中断程序 ****/
                    currentThread.interrupt();
                }
            }
        };
        Thread runnable = new Thread(runnableThreadImp);
        runnable.start();

        try {
            Thread.sleep(5); // 让主线程休眠20ms
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        // 请求中断线程,即设置当前线程的中断状态为true
        // 当此方法尝试中断一个处于阻塞状态的线程时,该线程会抛出一个异常 InterruptedException
        // 并将此线程的中断状态,清除为false
        runnable.interrupt();
    }
}

image.png

看上图的执行效果,我们可以看得出在catch 中重新执行currentThread.interrupt()是可以正常的中断程序的。

结语

如果这篇文章帮到了你,欢迎点赞👍和关注⭐️。

文章如有错误之处,希望在评论区指正🙏🙏

欢迎关注我的微信公众号,一起交流技术,微信搜索 🔍 :「 五十年以后