interrupt

317 阅读4分钟

interrupt()

public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();          // 仅仅设置interrupt标志位
                b.interrupt(this);  // 调用如 I/O 操作定义的中断方法
                return;
            }
        }
        interrupt0();
    }

 // 仅仅设置interrupt标志位
private native void interrupt0();
  1. interrupt 中断操作时,非自身中断需要先检测是否有中断权限,这由jvm的安全机制配置;

  2. 同步阻塞判断blocker是不是null,如果不是 先设置中断标志,然后调用如 I/O 操作定义的中断方法 然后返回,什么情况下 blocker不是null呢,或者说什么时候会退出被阻塞状态呢

    如果线程处于sleep, wait,join等状态, 那么线程将立即退出被阻塞状态, 并抛出一个InterruptedException异常

 * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public static native void sleep(long millis) throws InterruptedException;

sleep是THread的方法,是个native方法

 * @exception  InterruptedException if any thread interrupted the
     *             current thread before or while the current thread
     *             was waiting for a notification.  The <i>interrupted
     *             status</i> of the current thread is cleared when
     *             this exception is thrown.
     * @see        java.lang.Object#notify()
     * @see        java.lang.Object#notifyAll()
     */
    public final native void wait(long timeout) throws InterruptedException;

wait是Object的方法,也是个native方法

* @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

join方法也是Thread类的方法,看它实现他最终是会调用Obj.wait方法

综上所述和native的注释,当线程处于sleep, wait,join时,如果线程中断,线程会抛出InterruptedException并清除中断状态

* <p> If a thread's interrupt status is already set and it invokes a blocking
 * I/O operation upon a channel then the channel will be closed and the thread
 * will immediately receive a {@link ClosedByInterruptException}; its interrupt
 * status will remain set.
 *
 * <p> A channel supports asynchronous closing and interruption if, and only
 * if, it implements this interface.  This can be tested at runtime, if
 * necessary, via the <tt>instanceof</tt> operator.
 *
 *
 * @author Mark Reinhold
 * @author JSR-51 Expert Group
 * @since 1.4
 */

public interface InterruptibleChannel
    extends Channel
{

    /**
     * Closes this channel.
     *
     * <p> Any thread currently blocked in an I/O operation upon this channel
     * will receive an {@link AsynchronousCloseException}.
     *
     * <p> This method otherwise behaves exactly as specified by the {@link
     * Channel#close Channel} interface.  </p>
     *
     * @throws  IOException  If an I/O error occurs
     */
    public void close() throws IOException;

}
  1. java nio里的channel是实现自InterruptibleChannel接口的,这个接口的注释里有说明,当正在操作这个channel的线程被其他线程中断,则会close这个channel,当前(被中断的)线程抛出一个ClosedByInterruptException异常。具体的可以看sun.nio.ch.SocketChannelImpl.write 方法内部实现有判断中断标志
* <p> This method performs a blocking <a href="#selop">selection
     * operation</a>.  It returns only after at least one channel is selected,
     * this selector's {@link #wakeup wakeup} method is invoked, or the current
     * thread is interrupted, whichever comes first.  </p>
     *
     * @return  The number of keys, possibly zero,
     *          whose ready-operation sets were updated
     *
     * @throws  IOException
     *          If an I/O error occurs
     *
     * @throws  ClosedSelectorException
     *          If this selector is closed
     */
    public abstract int select() throws IOException;
  1. 如果线程在Selector上被阻塞,如果interrupted,select方法将立即返回不会抛出异常
  2. 如果非以上情况,将直接标记 interrupt 状态

小结:interrupt()只有再2、3、4的情况下,线程中断标志后,线程才会抛出异常或者退出,并且清除中断状态,其他情况只会标记中断状态为true,不会中断线程,程序可以自己根据中断标志做出对应的处理

interrupted()、isInterrupted()

//静态方法,调用该方法调用后会清除中断状态
public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

 // 这个方法不会清除中断状态
 public boolean isInterrupted() {
        return isInterrupted(false);
    }

//返回中断状态标志,参数代表是否清除中断状态    
private native boolean isInterrupted(boolean ClearInterrupted);
  • interrupted()
    这是个静态方法,返回中断状态标志,并清除中断状态
  • isInterrupted
    返回中断状态标志,不清除中断状态

代码示例

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        StopThread thread = new StopThread();
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
    }

    private static class StopThread extends Thread {
        @Override
        public void run() {
            try {
                // 休眠3秒,模拟耗时操作
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("当前线程状态:" + Thread.currentThread().isInterrupted());
        }
    }
}

    1.线程进入sleep状态
    2.线程中断标志
    3.线程抛出异常并清除中断状态
    4.打印中断状态为false
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        StopThread thread = new StopThread();
        thread.start();

    }

    private static class StopThread extends Thread {
        @Override
        public void run() {
            Thread.currentThread().interrupt();
            System.out.println("1当前线程状态:" + Thread.currentThread().isInterrupted());
            System.out.println("2当前线程状态:" + Thread.interrupted());
            System.out.println("3当前线程状态:" + Thread.currentThread().isInterrupted());
        }
    }
}

    1.线程中断标志
    2.返回线程中断状态为true,不清除中断状态
    3.返回线程中断状态为true,并清除中断状态
    4.返回线程中断状态为false