interrupt()方法是thread里的一个方法,具体先看源码注释
1.方法描述
/**
* Interrupts this thread.
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link java.nio.channels.Selector}
* then the thread's interrupt status will be set and it will return
* immediately from the selection operation, possibly with a non-zero
* value, just as if the selector's {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
*
* <p> Interrupting a thread that is not alive need not have any effect.
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
从描述中可以看出,这个方法有多种情况
1.在线程处于wait,join,sleep方法阻塞时被调用
将会抛出InterruptedException异常并清除中断状态(即设置为false)
2.在线程处于io方法阻塞时被调用(java.nio.channels.InterruptibleChannel)
通道将被关闭,将会抛出ClosedByInterruptException异常并设置中断状态为true
3.在线程处于选择器中被调用(java.nio.channels.Selector)
中断状态将被设置为true,线程立即从选择操作中返回,可能有一个非0值,就像选择器的(java.nio.channels.Selector#wakeup)方法被调用一样
4.如果前面的条件都不成立,那么这个线程的中断状态将设置为true。
2.具体实现
如何做到的呢,看一下代码
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();
}
首先,调用a线程中断方法的若不是a线程本身,则先检查权限
在锁代码中,检查blocker变量,
blocker通过blockedOn()方法设置
/* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
*/
void blockedOn(Interruptible b) {
synchronized (blockerLock) {
blocker = b;
}
}
看注释,这里是说nio中导致线程阻塞时会设置这一变量
然后判断blocker这一成员变量是否为null
如果是,则调用blocker.interrupt(a线程);这一方法,那根据blocker这一变量的多态性即可实现上面说的有关nio的多种情况(即nio.channels.InterruptibleChannel;nio.channels.Selector为线程设置阻塞状态时产生的blocker不一样)
继续,点进 b.interrupt(this);看
public abstract interface sun.nio.ch.Interruptible {
// Method descriptor #7 (Ljava/lang/Thread;)V
public abstract void interrupt(java.lang.Thread arg0);
}
果然只是个抽象方法,看实现有两种
1.AbstractInterruptibleChannel
protected final void begin() {
if (interruptor == null) {
interruptor = new Interruptible() {
public void interrupt(Thread target) {
synchronized (closeLock) {
if (!open)
return;
open = false;
interrupted = target;
try {
AbstractInterruptibleChannel.this.implCloseChannel();
} catch (IOException x) { }
}
}};
}
blockedOn(interruptor);
Thread me = Thread.currentThread();
if (me.isInterrupted())
interruptor.interrupt(me);
}
看起来是关闭通道的样子,嗯,注释没忽悠我
2.AbstractSelector
protected final void begin() {
if (interruptor == null) {
interruptor = new Interruptible() {
public void interrupt(Thread ignore) {
AbstractSelector.this.wakeup();
}};
}
AbstractInterruptibleChannel.blockedOn(interruptor);
Thread me = Thread.currentThread();
if (me.isInterrupted())
interruptor.interrupt(me);
}
…和选择器调用wakeup方法效果一模一样,只是调用了一下而已
interrupt0()
那interrupt0()又是什么意思呢,
private native void interrupt0();
是一个本地方法,查了下,大概是以下意思
首先检查线程是否处于wait,sleep,join时设置的线程状态位,设置为a
//把线程中断状态设置为true
if(a){
//把线程中断状态设置为false
//抛出InterruptedException异常
}
所以,这就是为什么catch(InterruptedException e) 后,线程中断状态依然为false的原因
3.demo
public static void main(String[] args) throws InterruptedException {
InterruptedThread i = new InterruptedThread();
OtherThread o = new OtherThread(i);
i.start();
o.start();
}
public class InterruptedThread extends Thread {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
sleep(1000);
} catch (InterruptedException e) {
System.out.println("catch处理前:" + currentThread().isInterrupted());
currentThread().interrupt();
e.printStackTrace();
System.out.println("catch处理后:" + currentThread().isInterrupted());
}
}
}
}
public class OtherThread extends Thread {
private InterruptedThread interruptedThread;
public OtherThread(InterruptedThread interruptedThread) {
this.interruptedThread = interruptedThread;
}
@Override
public void run() {
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("o线程处理前:" + interruptedThread.isInterrupted());
interruptedThread.interrupt();
System.out.println("o线程处理后:" + interruptedThread.isInterrupted());
}
}
执行,输出内容如下:
o线程处理前:false
o线程处理后:true
catch处理前:false
catch处理后:true
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at thread.InterruptedThread.run(InterruptedThread.java:8)
首先,需要在阻塞时被中断的线程i在run里启动while循环,检查条件是!Thread.currentThread().isInterrupted(),这一方法会返回当前线程的中断状态;
o线程在需要中断i时,调用i线程的interrupt()方法;
这样,i线程被从sleep的阻塞态唤醒,抛出InterruptedException异常,但是此时又把i线程的中断状态重置为false,所以我们在catch里再把中断状态设置为true,此时,在下一次while循环时条件不满足,退出循环,结束线程