这一篇着重分析下线程中断,在C.U.T中,中断是用的比较多的一种技术手段,运用的好能带来很多的便利。
1.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.如果不是当前线程中断自己,需要checkAccess。
2.如果线程在调用Object类的wait(),join(),sleep()方法过程中受阻,则其中断状态将被清除,同时还收到一个InterruptException。
3.如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException。
4.如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。
备注:3,4两点本人没什么经验,上述的描述是从jdk api摘抄过来的。一般大家注意下第二点就行。
2.interrupted()
测试当前线程是否已中断。线程的中断状态由该方法擦除。也就是如果两次调用该方法,则第二次会返回false
public static boolean interrupted() { return currentThread().isInterrupted(true); }
3.isInterrupted()
测试线程是否已被中断,但是线程的状态不受此方法影响。也就是说这个方法不会进行擦除操作
public boolean isInterrupted() { return isInterrupted(false); }主要的区分就是isInterrupt的调用参数,一个数true,一个是false。
/** * Tests if some Thread has been interrupted. The interrupted state * is reset or not based on the value of ClearInterrupted that is * passed. */ private native boolean isInterrupted(boolean ClearInterrupted);
以上就是api内对3个方法的解释,我相信已经很清楚了,没有必要做过多的解释。
以下就是进行一些测试,来分析一下自己的理解。
测试一、使用isInterrupted判断线程状态
public class TestA { public static void main(String[] args) { T2 t2 = new T2(); t2.start(); try{ Thread.sleep(2000); //主线程执行2S睡眠,保证t2线程能够正常执行一段时间 }catch (Exception e){ System.out.println("main exception"); } t2.interrupt(); //通知t2,你中断了 } } class T2 extends Thread { @Override public void run() { while (true){ if(Thread.currentThread().isInterrupted()){ System.out.println("111111111"); }else { System.out.println("22222222"); } System.out.println("33333333333333"); } } }
22222222 33333333333333 22222222 33333333333333 22222222 33333333333333 ... ... 111111111 33333333333333 111111111 33333333333333 111111111 33333333333333 ... ...
结果分析:
可以看见在main线程睡眠的那2秒中内,t2线程在正常执行(输出2,3),当t2进行了中断操作时,输出了(1,3),而我们调用的是isInterrupted方法,这个方法是不会擦除状态的, 同时也要注意,t2线程一直在运行中,没有真正的中断。只是有了一个中断状态而已。在Core Java中有这样一句话:"没有任何语言方面的需求要求一个被中断的程序应该终止。中断一个线程只是为了引起该线程的注意,被中断线程可以决定如何应对中断 "
测试二、阻塞方法调用时执行interrupt
public class TestA { public static void main(String[] args) { T2 t2 = new T2(); t2.start(); try{ Thread.sleep(6000); //主线程执行2S睡眠,保证t2线程能够正常执行一段时间 }catch (Exception e){ System.out.println("main exception"); } t2.interrupt(); //通知t2,你中断了 } } class T2 extends Thread { @Override public void run() { System.out.println("t2 into sleeping"); try{ Thread.sleep(20000); System.out.println("t2 wake up"); }catch (InterruptedException e){ System.out.println("oh,shit! exception"); return; } System.out.println("oh,shit! exception"); } }
t2 into sleeping oh,shit! exception
此测试用例就是测试interrupt方法中API的关于wait,join,sleep方法,如果在调用时发出interrupt指令时,会直接抛出InterruptException。
测试三、阻塞方法调用前执行interrupt方法
public class TestA { public static void main(String[] args) { System.out.println("main start"); Thread.currentThread().interrupt(); try{ System.out.println("main exe sleep"); Thread.sleep(6000); //主线程执行2S睡眠,保证t2线程能够正常执行一段时间 System.out.println("after main exe sleep"); }catch (InterruptedException e){ System.out.println("oh! shit Exception"); } System.out.println("main end"); } }
main start main exe sleep oh! shit Exception main end也可以很明显的看见,当主线程执行过interrupt方法之后,如果再执行sleep,wait,join等方法的话,会得到一个InterruptException。
测试四:isInterrupted方法的细节测试
public class TestA { public static void main(String[] args) { System.out.println("main start"); Thread.currentThread().interrupt(); try{ System.out.println("main exe sleep"); System.out.println("main state111: "+Thread.currentThread().isInterrupted()); Thread.sleep(6000); //主线程执行2S睡眠,保证t2线程能够正常执行一段时间 System.out.println("after main exe sleep"); }catch (InterruptedException e){ System.out.println("oh! shit Exception"); System.out.println("main state222: "+Thread.currentThread().isInterrupted()); System.out.println("main state333: "+Thread.currentThread().isInterrupted()); } System.out.println("main end"); } }
main start main exe sleep main state111: true oh! shit Exception main state222: false main state333: false main end我们发现,isInterrupted方法只能使用一次,第一次使用时能发现线程处于中断状态了,但是当执行过sleep之后呢,中断状态被擦除了,因此再次判断肯定是false。
测试五、测试interrupted方法
public class TestA { public static void main(String[] args) { System.out.println("main start"); System.out.println("main state11: "+Thread.interrupted()); Thread.currentThread().interrupt(); System.out.println("main state22: "+Thread.interrupted()); System.out.println("main state33: "+Thread.interrupted()); System.out.println("main end"); } }
main start main state11: false main state22: true main state33: false main end可以发现,当第一次当第二次调用时,可以判断出当前线程处于中断状态了,但是再一次调用时确发现返回了false,因为它做了擦除动作。