Java线程中断的原理

2018-12-04  本文已影响15人  tracy_668

在java中不提供抢占式中断,也就是说不允许线程之间的直接抢占,(已经有过Thread.stop,Thread.suspend等API都已经被废弃, 容易导致各种问题。。) ,java提供的是协作式中断, “协作“是指在中断发生时,系统(JVM)会改变中断标记,但并不强制应用程序中断。对应用程序来说,需要主动检查中断标记,并最终决定是否中断。 所以完成这类中断,需要系统和应用程序共同”协作“。 此外,线程阻塞时,系统发起的InterruptedException也可以看做一种强制式的中断。因为,在这种情况下,不管线程是否同意,系统都会强制解除线程阻塞,可以简单理解为就是轮询某个表示中断的标记,我们在任何普通的代码中都可以实现,例如:

 volatile bool isInterrupted;
    //…
    while(!isInterrupted) {
        compute();


    }

上述的代码问题也很明显。利用轮询检查标志变量的方式,在wait和sleep等线程阻塞操作中,无法感知中断,常常需要再sleep,wait过程中能感知发生了中断,显然我们自己实现的代码无法实现。要想让中断及时被响应,必须在虚拟机底层进行线程调度时对标记变量进行检查,JVM中确实是这样做的。下面摘自java.lang.Thread的源代码:

 public static boolean interrupted() {

            return currentThread().isInterrupted(true);

        }



       //…

        private native boolean isInterrupted(boolean ClearInterrupted);
可以发现,isInterrupted被声明为native方法,取决于JVM底层的实现。  实际上,JVM内部确实为每个线程维护了一个中断标记。但应用程序不能直接访问这个中断变量,必须通过下面几个方法进行操作:
  public class Thread {

        //设置中断标记

        public void interrupt() { ... }  

        //获取中断标记的值

        public boolean isInterrupted() { ... }

        //清除中断标记,并返回上一次中断标记的值

        public static boolean interrupted() { ... }   

        ...

    }

通常情况下,调用线程的interrupt方法,并不能立即引发中断,只是设置了JVM内部的中断标记。因此,通过检查中断标记,应用程序可以做一些特殊操作,也可以完全忽略中断。 在执行涉及线程调度的阻塞调用时(例如wait、sleep和join),如果发生中断,被阻塞线程会“尽可能快的”抛出InterruptedException。因此,我们就可以用下面的代码框架来处理线程阻塞中断:

  try {

        //wait、sleep或join

    }

    catch(InterruptedException e) {

        //某些中断处理工作

    }

所谓“尽可能快”,应该就是JVM在线程调度调度的间隙检查中断变量,速度取决于JVM的实现和硬件的性能。

上一篇 下一篇

猜你喜欢

热点阅读