线程的interrupt()方法解析

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循环时条件不满足,退出循环,结束线程

猜你喜欢

转载自blog.csdn.net/qq_24516549/article/details/88849065
今日推荐