这一篇着重分析下线程中断,在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,因为它做了擦除动作。