java中断机制

1. 简述

看了很多篇关于java中断机制的博文,这里用自己的语言简单总结下,希望可以方便大家快速理解。
详细请参考:
http://www.infoq.com/cn/articles/java-interrupt-mechanism
http://www.cnblogs.com/carmanloneliness/p/3516405.html

2. 线程的关闭

线程的关闭有三种方法:

  1. Thread.stop()。不安全,已过时。参考: http://blog.csdn.net/kingzma/article/details/45739963
  2. 设置标志位,控制线程关闭,但不能做到对阻塞线程或者运行时间很长的方法的关闭
  3. interrupt()方法关闭,对于阻塞线程,会“几乎”立即关闭。对于非阻塞线程,需要通过调用isInterrupted()方法实时监测中断标志位来手动地关闭线程(原理同2)。

本文主要从方法三入手,从源代码角度,详细说明java中断机制。

3. 中断简述

java中断是一种协作式的中断,也就是说,调用interrupt()方法并不代表着直接中断该线程。而仅仅是更改了“中断标志位”,具体是否中断由线程决定。
关于中断,Thread类中有如下几个方法:

方法名功能
public void interrupt()中断线程
public static boolean interrupted()测试当前线程是否已经中断
public boolean isInterrupted()测试线程是否已经中断
private native boolean isInterrupted(boolean ClearInterrupted)测试线程是否已经中断并选择是否重置中断标志

3.1 private volatile Interruptible blocker成员

在详细讲解上述四种方法之前,首先了解一下Thread类中的一个重要成员:private volatile Interruptible blocker。是的,这个blocker对象,便是所谓的“中断标志位”。关于这个中断标志位,有如下三个操作:

  1. 默认blocker=null; 
  2. 调用方法“interrupt0();”将会导致“该线程的中断状态将被设置(JDK文档中术语)”。
  3. 再次调用“interrupt0();”将会导致“其中断状态将被清除(同JDK文档中术语)”

通过反复调用interrupt0()方法,会将blocker的值在true和false之间来回设置。

另外,Interruptible类中也有一个interrupt()方法,没有找到该方法的源码。根据博文 Java多线程之interrupt()的深度研究,该方法负责真正地打断线程,并且跑出InterruptedException异常,这一点会在下面详述。

3.2 isInterrupted(boolean ClearInterrupted)方法

这个方法是个私有的native方法,主要用于Thread类中的其他方法调用。

检测中断标志位,判断线程是否被中断。根据传入参数,决定是否重置中断标志位。如果参数为true,则重置中断标志位为false,否则不改变中断标志位。

3.3 public boolean isInterrupted()方法

测试线程是否已经中断。线程的中断状态不受该方法的影响。线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

    public boolean isInterrupted() {
        return isInterrupted(false);
    }

源码即调用isInterrupted(false),不改变中断标志位。

3.4 public static boolean interrupted()方法

这是一个静态方法,所以它仅能执行该方法的语句所在的线程,与调用该方法的对象无关。具体可参考我的另一篇小文章 由sleep()谈多线程中的静态方法

interrupted()方法测试“当前”线程是否已经中断,线程的中断状态 由该方法清除,线程中断被忽略,因为在中断时不处于活动状态的线程将由此返回 false 的方法反映出来。

    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

从源码便可以看出,该方法仅能控制当前线程,值得一提的是currentThread()方法也是一个静态方法。

不难理解,连续调用两次interrupted()方法之后,其返回值一定是false。

初始状态-第一次调用-第二次调用
中断标志位:true调用interrupted()中断标志位:false第二次调用中断标志位:false
返回值:true返回值:false
中断标志位:false调用interrupted()中断标志位:false第二次调用中断标志位:false
返回值:false返回值:false

3.5 public void interrupt()方法

        public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

下面用两张图分别解释为什么

1.调用interrupt()方法并不会中断一个正在运行的线程.
2.若调用sleep()而使线程处于阻塞状态,这时调用interrupt()方法,会抛出InterruptedException,从而使线程提前结束阻塞状态,退出阻塞代码。

Created with Raphaël 2.1.0 调用interrupt()方法 是否是阻塞线程? 见下图 进入interrupt()方法,判断b为空,不能进入if语句。 调用interrupt()方法,将blocker置为true。 End yes no
Created with Raphaël 2.1.0 调用interrupt()方法 是否是阻塞线程? sleep()、wait()、join()等阻塞方法中,调用interrupt0()方法,将blocker置为true。 interrupt()方法中,判断b非空,进入if语句。 if()语句中,调用interrupt0()方法,将blocker置为false。 if()语句中,调用Interruptible类的interrupt()方法,真正的关闭该线程。并抛出InterruptedException异常。 End 见上图 yes no

4. 一个疑问(可略过)

下面是笔者测试代码的时候遇到的一个问题,如果读者有兴趣烦请不吝赐教。

4.1 测试代码一:


public class Test1 {
    private static Object obj;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread("中断") {
            public void run() {
                try {
                        sleep(1000*5);
                } catch (InterruptedException e) {

                }
            }
        };
        t1.start();
        //Thread.sleep(1);
        System.out.println(t1.isInterrupted());
        t1.interrupt();
        System.out.println(t1.isInterrupted());
        Thread.sleep(50);
        System.out.println(t1.isInterrupted());
    }
}

测试结果:false,true,false。
不难理解,调用interrupt( )之后,由于t1线程是阻塞线程,所以其blocker被置为true,主线程sleep(50)的时间内,完成了线程的停止工作,blocker为false。

4.2 测试代码二:

将测试代码一种的注释行取消注释,即在t1.start()之后,让主线程sleep(1)。

测试结果:false,true,false。

4.3 测试代码三:

将测试代码二中的sleep(1)改为sleep(100)。

测试结果:false,false,false。

疑问:t1.interrupt()语句是在Thread.sleep()语句之后执行的,为什么睡眠时间会对下一句的中断状态产生影响?

本人测试机器较卡,在另一台机器上,使用sleep(1)测试出来的结果也是false,false,false。

希望可以得到帮助,教学相长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值