Java中的线程中断机制

Java的线程用于并发执行任务。之前对线程这一块,一直没搞懂的就是中断这一块,什么interrupt(), interrupted(), isInterrupted()这几个方法,InterruptedException这个异常,一直没搞明白。今天读《Java并发编程实战》里面也说到了InterruptedException,于是又到网上找资料认真读了一下,这次终于搞懂了,于是记录一下。

一.Java线程的中断

其实Java的线程并没有一个真正的状态叫做“中断”终态,也就是说线程不会因为被“中断”或者从“中断”中恢复就自动改变任何行为,中断只是一种不同线程之间进行协作的协议,是一种约定机制,而不是强制的行为。为什么这么说呢?在Java中,每一个线程都有一个内部的布尔状态位(是由JVM维护的,在jdk源代码中是看不到的),它为false时代表线程没有被中断,它为true时代表线程被中断了。但是当这个状态位在true和false之间来回变时,线程是不会自己改变任何行为的。那么它的作用是什么呢?

二.Java中操作中断的几种方法

Java中跟这个状态位直接相关的方法有如下几个:

interrupt(), interrupted(), isInterrupted。

首先说isInterrupted(),它的作用是读取中断状态位的值,以此来判断当前被调用这个方法的线程实例是否处于中断状态。如果返回true,说明被中断了,如果返回false,说明没有被中断。除此之外,它什么都不做。

其次是interrupted(),它的作用跟isInterrupted()是一样的,也是去读中断状态位的值,以此判断调用它的线程实例是否处于中断状态。但它还有一个副作用,就是每次调用的时候,都会将中断状态位重置为false。也就是说,假如线程被中断了,那么调用它会返回true。但如果你再次调用它,或者调用isInterrupted(),即使没有其他线程来中断它,那也会返回false。

最后是interrupt(),这个方法就是单纯的将调用它的线程的中断状态置为true,也就是通常说的中断了这个线程。

三.线程中断的作用

通过上述文字,我们可以看出,中断与否,其实只是修改线程的一个状态位而已,JVM并不会因此去改变线程的执行。那么中断的意义在哪里呢?答案是它是一种线程之间的协作机制。一个线程在可以对另一个线程发起中断,代表这个线程的一种请求,也就是说“如果您觉得方便的话,麻烦处理一下这个中断”,另一个线程可以选择是否关心中断状态,决定发生中断时应该如何处理。例如当一个线程一直在阻塞等待获得一个锁,这是另一个线程可以将它中断。而被正确设计的阻塞的线程,会不断的去轮询这个中断状态,发现中断时可以选择取消等待,也可以选择不理会,继续等待。

四.线程对中断的一般处理方式。

首先是线程自己轮询中断状态之后,发现自己被中断之后的处理:

1.置之不理,继续执行自己的任务,适用于一些不能被中断的任务,但有可能在执行完之后,将自身的状态置为中断,以供更高层的调用栈处理中断。

2.抛出InterruptedException。过去看书的时候,总是搞不懂这个InterruptedException是怎么抛出来的。现在明白了,其实这个异常,也是人为抛出来的,话句话说,是设计程序的人想让它抛,它才能抛。它的作用就在于,告诉捕获到它的上层调用,我被中断了。这样做往往是一种比较好的方式,因为发生中断时,往往任务本身没法处理,交给更上层调用者是一个可行的选择。

其次是捕获到InterruptedException异常的处理:

1.生吞异常,也就是捕获之后,不做任何有效的处理,包括不把自己的中断状态位再次置为中断,以让上层调用栈感知中断,也不将异常继续往上抛。这种情况可能发生在Runnable接口的run方法内,因为run方法不能抛出异常。

2.将异常上抛,如果自己无法处理中断,就将这个异常往上抛,交给有能力处理的调用者。

3.将自己的中断状态位置为中断。理由如上,是为了让上层调用栈能感知中断。

五.线程中断的应用

线程的中断在很多阻塞方法中都有应用,例如AQS中的await方法,线程池中,阻塞队列中等。从这些方法可以看出,中断一般是用于会阻塞的方法,比如阻塞等待获取锁,阻塞从队列中获取元素等。后续我会结合中断机制研究这些类的源代码。

六.示例

下面给出一个Java中断的示例[1]:

class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 500000000; i++) {
            if (this.isInterrupted()) {
                System.out.println("should be stopped and exit");
                if (this.isInterrupted()) {
                    System.out.println("the interrupt status was not cleared, so it is interrupted");
                }
                break;
            }
            System.out.println("i=" + (i + 1));
        }
        System.out.println("this line is also executed. thread does not stopped");
    }
}

public class InterruptTest {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            TimeUnit.MILLISECONDS.sleep(20);
            thread.interrupt();
            while (true) {
                if (thread.isInterrupted()) {
                    System.out.println("main catch interrupt");
                    break;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        } catch (RuntimeException e) {
            System.out.println("print");
            e.printStackTrace();
        }
        System.out.println("end!");
    }
}

输出:

MyThread运行到中间的时候会被中断,并作出了结束退出循环的响应。

总结:

本文是对自己学习线程中断机制的总结,文字都是用自己的话写的,有的可能不是很专业的名词。但是这代表了自己思考过了,而不是从网上各种抄官方的定义。我感觉这样的文章更有意义一点吧,否则就千文一面了。

参考:

1.https://www.cnblogs.com/hapjin/p/5450779.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值