interrupt、interrupted、isInterrupted方法详解
interrupt方法的源码:
public void interrupt() {if (this != Thread.currentThread())checkAccess();synchronized (blockerLock) {Interruptible b = blocker;if (b != null) {interrupt0(); //仅仅对当前线程的中断位进行标记b.interrupt();return;}}interrupt0(); // Just to set the interrupt flag
}
源码说明:
private volatile Interruptible blocker;
private native void interrupt0();
变量blocker表示中断状态(interrupt status),blocker的值默认是null。 interrupt0()方法是本地方法,其作用是仅仅对当前线程的中断位进行标记。线程的中断标志位默认是false,interrupt0()方法将线程的中断标志位设置为true,设置线程的中断状态。清除线程的中断状态,就是将中断标志位设置为false。
当线程调用interrupt方法时,会进入到同步代码块中,由于blocker==null,所以不执行if语句中的代码,而是调用interrupt0()方法,将线程的中断标志位设置为true。所以调用interrupt方法不能中断线程,只是设置线程的中断状态。
调用sleep、wait或join等方法的线程,如果再调用interrupt方法,将会抛出InterruptedException异常,或者调用interrupt方法的线程,如果再调用sleep、wait或join等方法,也会抛出InterruptedException异常。
interrupted和isInterrupted方法的源码:
public static boolean interrupted() {return currentThread().isInterrupted(true);
}public boolean isInterrupted() {return isInterrupted(false);
}private native boolean isInterrupted(boolean ClearInterrupted);
interrupted和isInterrupted方法的相同点都是判断线程的中断状态(interrupted status)是否被设置(即标志位是否为true),若被设置返回true,否则返回false。区别有两点:一:前者是static方法,调用者是current thread,而后者是普通方法,调用者是this thread。二:它们其实都调用了Java中的一个native方法isInterrupted(boolean ClearInterrupted); 不同的是前者传入了参数true,后者传入了false,意义就是:前者将清除线程的interrupt state(将线程的中断标志位设置为false),后者对线程的interrupt state没有影响。
public void interrupt();
向线程发送中断请求,线程的中断标志位将被设置为true。如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者Thread类的join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,将抛出InterruptedException异常,且线程的中断状态将被清除。
调用interrupt方法是在线程中打了一个停止标志,并不是真的停止线程。其作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。可通过interrupted和isInterrupted方法判断中断标志,进而结束线程。此线程是指调用interrupt方法的线程,如Thread t = new Thread();t.interrupt();线程t调用了interrupt方法,所以此线程就是指线程t。
public static boolean interrupted();
如果当前线程已经中断,则返回 true;否则返回 false。
interrupted方法的作用是测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态。由于第一次调用interrupted方法时,中断状态已经被清除,第二次再调用interrupted方法时将返回一个false。在哪个线程中调用了interrupted方法,该线程就是当前线程,如在main线程中有如下语句,Thread t = new Thread();t.interrupted();虽然是线程t调用了interrupted方法,但是,是在main线程中调用的interrupted方法,main线程就是当前线程。
public boolean isInterrupted();
如果此线程已经中断,则返回 true;否则返回 false。
测试线程是否已经中断,线程的中断状态不受该方法的影响。作用是只测试此线程是否被中断,不清除中断状态。此线程是指调用isInterrupted方法的线程,如在main线程中有如下语句,Thread t = new Thread();t.isInterrupted();即使是在main线程中,但线程t调用了isInterrupted方法,所以此线程就是指线程t。
interrupted与isInterrupted方法的区别:interrupted方法是判断当前线程是否被中断,并清除中断状态,而isInterrupted方法是判断此线程是否被中断,不清除中断状态。
示例:
public class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println("i="+(i+1));}}
}public class Test{public static void main(String[] args ) {MyThread thread=new MyThread();thread.start();thread.interrupt();System.out.println("第一次调用thread.isInterrupted():"+thread.isInterrupted());System.out.println("第二次调用thread.isInterrupted():"+thread.isInterrupted());//测试interrupted()函数System.out.println("第一次调用thread.interrupted():"+thread.interrupted());System.out.println("第二次调用thread.interrupted():"+thread.interrupted());System.out.println("thread是否存活:"+thread.isAlive());}
}
测试结果如下所示:
thread线程调用了interrupt方法,并没有使thread线程立即中断,只是将thread线程的中断标志设置为true(线程的中断状态被设置),通过thread.isInterrupted方法判断线程的中断状态是否被设置,若被设置了,则返回true,否则返回false。从输出结果看,可能会有疑惑,为什么后面两个interrupted方法输出的都是false,而不是预料中的一个true一个false?注意!!!这是一个坑!!!上面说到,interrupted方法测试的是当前线程是否被中断,这里当前线程是main线程,而thread.interrupt中断的是thread线程,这里的此线程就是thread线程。所以当前线程main从未被中断过,尽管interrupted方法是以thread.interrupted的形式被调用,但它检测的仍然是main线程而不是检测thread线程,所以thread.interrupted在这里相当于main.interrupted。
若调用sleep()而使线程处于阻塞状态,这时调用interrupt()方法,会抛出InterruptedException,从而使线程提前结束阻塞状态,退出阻塞代码。为什么?
1.默认blocker=null; ®1
2.调用方法“interrupt0();”将会导致“该线程的中断状态将被设置(JDK文档中术语)”。®2
3.再次调用“interrupt0();”将会导致“其中断状态将被清除(JDK文档中术语)”®3
异常其实是interrupt()抛出的,而不是sleep()抛出的。