java线程中断

150 阅读3分钟

线程状态

我们在java.lang.Thread类中可以找到一个状态枚举类

public enum State {
    /**
     * Thread state for a thread which has not yet started.
     */
    NEW,

    /**
     * Thread state for a runnable thread.  A thread in the runnable
     * state is executing in the Java virtual machine but it may
     * be waiting for other resources from the operating system
     * such as processor.
     */
    RUNNABLE,

    /**
     * Thread state for a thread blocked waiting for a monitor lock.
     * A thread in the blocked state is waiting for a monitor lock
     * to enter a synchronized block/method or
     * reenter a synchronized block/method after calling
     * {@link Object#wait() Object.wait}.
     */
    BLOCKED,

    /**
     * Thread state for a waiting thread.
     * A thread is in the waiting state due to calling one of the
     * following methods:
     * <ul>
     *   <li>{@link Object#wait() Object.wait} with no timeout</li>
     *   <li>{@link #join() Thread.join} with no timeout</li>
     *   <li>{@link LockSupport#park() LockSupport.park}</li>
     * </ul>
     *
     * <p>A thread in the waiting state is waiting for another thread to
     * perform a particular action.
     *
     * For example, a thread that has called <tt>Object.wait()</tt>
     * on an object is waiting for another thread to call
     * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
     * that object. A thread that has called <tt>Thread.join()</tt>
     * is waiting for a specified thread to terminate.
     */
    WAITING,

    /**
     * Thread state for a waiting thread with a specified waiting time.
     * A thread is in the timed waiting state due to calling one of
     * the following methods with a specified positive waiting time:
     * <ul>
     *   <li>{@link #sleep Thread.sleep}</li>
     *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
     *   <li>{@link #join(long) Thread.join} with timeout</li>
     *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
     *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
     * </ul>
     */
    TIMED_WAITING,

    /**
     * Thread state for a terminated thread.
     * The thread has completed execution.
     */
    TERMINATED;
}

线程执行

  1. java线程模型其实是对应的底层操作系统的线程模型,线程也就是系统的一个资源。 资源是宝贵的,所以线程池使用必不可少的

  2. 线程的调度模型是抢占式,也就是由cpu来分配时间片,什么时间分配和分配多少由操作系统来分配。

    获取到时间片就会去执行,时间片执行完成之后,再继续需要获取时间片分配。

线程中断机制

Java没有提供一种安全、直接的方法来停止某个线程,而是提供了中断机制。 中断机制是一种协作机制,通过给当前线程设置一个中断标识,不过中断标识并不能直接终止另一个线程,而需要被中断的线程自己处理

中断标识

调用线程实例方法t.interrupt()就可以对线程标识一个中断标识interrupt=true.这时候有如下几种情况:

  1. 当线程处于WAITING,TIMED_WAITING,即调用声明InterruptedException的方法,就可以随即抛出一个InterruptedException。
 public static native void sleep(long millis) throws InterruptedException; 
 public final void wait() throws InterruptedException
  1. 不响应中断 当线程状态处于BLOCKED状态(特指线程进入synchronized等待队列中),若此时中断标识=true,并不会做出任何事,当线程被notify唤醒并且获取同步锁进入同步块时,也不会主动抛出异常,此时需要在线程中自己根据线程中断状态来处理
Object lock = new Object();
synchronized(lock){
}
  1. 响应中断

ReentrantLock#lockInterruptibly -> AQS#acquireInterruptibly (所以lockInterruptibly声明了抛出中断异常throws InterruptedException,和sleep/wait类似)

在juc包中AQS类中提供了一个acquireInterruptibly

   private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())  
                    throw new InterruptedException();//(2)
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted(); //(1)
    }
  1. 当线程被LockSupport.unpark唤醒之后,会判断是否被中断
  2. 如果被中断,则会主动抛出InterruptedException

总结: AQS和synchronized区别:

  1. AQS提供响应中断,唤醒后主动抛出中断异常
  2. synchronized不响应中断,不会主动抛出中断异常,并且被唤醒后还需要获取同步锁之后,才能处理异常

java有关线程中断三个方法

t.interrupt();

设置线程中断标识flag=true

public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();
    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            //调用底层native方法,给当前线程标识一个interrupt flag
            interrupt0();           // Just to set the interrupt flag

            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}
private native void interrupt0();

Thread.interrupted();

public static boolean interrupted() {
    return currentThread().isInterrupted(clearInterrupt->true);
}

静态方法。判断当前线程是否中断(即判断flag==true), 如果已经中断,则清空标识 将flag重置为false.

则此时代表线程中断标识为false。

t.isInterrupted();

public boolean isInterrupted() {
    return isInterrupted(clearInterrupt->false);
}

判断线程t是否中断(即判断flag==true),不会处理中断标识

image.png