java · 2022-05-22 0

Java线程状态与中断

一、线程状态

线程状态有:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

  1. NEW,线程还没有开始运行
  2. RUNNABLE,线程正在 java 虚拟机运行
  3. BLOCKED,线程在等待锁进入同步代码块
  4. WAITING,线程执行 Object.wait、Thread.join、LockSupport.park 方法
  5. TIMED_WAITING,线程执行 Object.wait(timeout)、Thread.sleep(timeout) 方法
  6. TERMINATED,线程已经停止运行

二、中断

  • public boolean isInterrupted() 判断线程中断标识位
  • public void interrupt() 设置当前线程对象的中断标识位
  • public static boolean interrupted() 判断当前线程中断标识位,并清空中断标识位

1.public boolean isInterrupted()

每个线程都一个状态位用于标识当前线程对象是否是中断状态。isInterrupted是一个实例方法,主要用于判断当前线程对象的中断标志位是否被标记了,如果被标记了则返回true表示当前已经被中断,否则返回false。

底层调用的本地方法isInterrupted,传入一个boolean类型的参数,用于指定调用该方法之后是否需要清除该线程对象的中断标识位。可以看出来,调用isInterrupted并不会清除线程对象的中断标识位。

// Thread.java
public boolean isInterrupted() {
    return isInterrupted(false);
}

private native boolean isInterrupted(boolean ClearInterrupted);

2.public void interrupt()

interrupt是一个实例方法,该方法用于设置当前线程对象的中断标识位。

3.public static boolean interrupted()

是一个静态的方法,用于返回当前线程是否被中断,并清除中断标识位

// Thread.java
public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

4.线程状态与中断标识位

NEW 和 TERMINATED,这两个状态下调用中断方法来中断线程的时候,Java认为毫无意义,所以并不会设置线程的中断标识位

RUNNABLE,处于RUNNABLE状态的线程在遭遇中断操作的时候只会设置该线程的中断标志位,并不会让线程实际中断,想要本线程被实际中断,则需要用程序去判断

BLOCKED,当线程处于BLOCKED状态说明该线程由于竞争某个对象的锁失败而被挂在了该对象的阻塞队列上了。那么此时发起中断操作不会对该线程产生任何影响,依然只是设置中断标志位

WAITING/TIMED_WAITING,这两种状态本质上是同一种状态,只不过TIMED_WAITING在等待一段时间后会自动释放自己,而WAITING则是无限期等待,需要其他线程调用notify方法释放自己。但是他们都是线程在运行的过程中由于缺少某些条件而被挂起在某个对象的等待队列上。当这些线程遇到中断操作的时候,会抛出一个InterruptedException异常,并清空中断标志位

执行 Thread.sleep(millis),线程是 TIMED_WAITING 状态;执行 blockingQueue.put(e) 线程是 WAITING 状态;执行 blockingQueue.put(e, timeout, unit) 线程是 TIMED_WAITING 状态。

5.栗子

@Test
public void testInterrupt() throws InterruptedException {
    Thread thread = new Thread(() -> {
        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    thread.start();

    TimeUnit.SECONDS.sleep(1);

    thread.interrupt();

    TimeUnit.SECONDS.sleep(1);
}