Java线程状态

Java 线程的6个状态

// Thread.State 源码
public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
}

每个线程在时间点只能属于一种状态

NEW

线程尚未启动。即还未调用 start方法

Thread thread = new Thread();
System.out.println(thread.getState());

输出NEW

引申问题

  • 服务调用一个线程start可以吗?

  • 线程执行完毕,再调用 start 方法可以吗?

大难是都不可以,start 会判断 线程 的 threadStatus ,只要 != 0 会抛出异常。调用一次 start 后,threadStatus 的值会改变。

RUNNABLE

线程正在运行。可能再JVM中运行,也可能再等待CPU分配资源。

BLOCKED

阻塞状态。等待锁(monitor lock)的释放进入同步区(synchronized block/method)。

WAITING

等待状态。处于改状态下的线程需要其他线程唤醒(Object.notify() or Object.notifyAll() )

进入该状态的三种方法:

  • Object.wait with no timeout 使当前线程处于等待状态
  • Thread.join with no timeout 底层调用的是 Object.wait
  • LockSupport.park 禁止线程进行线程调度

TIMED_WAITING

带超时时间的等待状态。线程等待一个具体的事件,到期后自动唤醒。

进入改状态的方法:

  • Thread.sleep
  • Object.wait with timeout
  • Thread.join with timeout
  • LockSupport.parkNanos
  • LockSupport.parkUntil

TERMINATED

线程运行完毕。

状态转换

线程正常流程

NEW -> RUNNABLE-> TERMIATED

BLOCKED 与 RUNNABLE

线程进入 BLOCKED 状态是因为等待锁的释放。

下面有两个线程a和b,a获得了锁且暂未释放,此时b处于 BLOCKED 状态。


@Test
public void blockedTest() throws InterruptedException {

    Thread a = new Thread(this::testMethod, "a");
    Thread b = new Thread(this::testMethod, "b");

    a.start();
    Thread.sleep(100);
    b.start();
    Thread.sleep(100);
    System.out.println(a.getName() + ":" + a.getState()); // a:RUNNABLE
    System.out.println(b.getName() + ":" + b.getState()); // b:BLOCKED
}

// 同步方法争夺锁
private synchronized void testMethod() {
    for (; ; ) {
    }
}

要加入一些延迟,因为b 一开始也是 RUNNABLE状态。

a,b 线程启动后,a 线程先进入到 synchronized 块,拿到对象锁。

b线程需要等待对象锁释放,就进入到了 BLOCKED 状态。

WAITING 与 RUNNABLE

  • Object.wait()

调用 wait 方法 前线程必须持有对象锁

调用 wait 方法时,会释放当前的锁,直到其他线程调用notify/notifyAll唤醒等待锁的线程。

  • Thread.join

当前线程 等待 调用join方法的线程执行完毕。当前线程进入WAITING 状态

public void blockedTest() { a.start(); a.join();//a RUNNABLE 当前线程WAITING

​ //a执行完毕 a TERMINATED 当前线程 RUNNABLE

}

TIMED_WAITING 与 RUNNABLE

与 WAITING 与 RUNNABLE 转换类似,只是加上了等待超时的时间。

  • Thread.sleep

当前线程睡眠指定时间。并不会释放锁,时间到后,线程进入 RUNNABLE 状态。

线程中断

一些情况下,我们在线程启动后不想让他继续执行,就需要中断线程。Java 还没有安全直接的方法来停止线程,但 Java 提供了线程中断机制里处理需要中断线程的情况。

线程中断机制是一种协作机制。需要注意,通过中断操作并不能直接终止一个线程,而是通知需要被中断的线程自行处理

  • Thread.interrupt 中断线程,不会立即停止线程,设置线程的中断状态为 true
  • Thread.currentThread().isInterrupted() 测试当前线程是否被中断。调用后会重置线程中断状态为false。
  • Thread.isInterrupted():测试当前线程是否被中断。与上面方法区别是不会影响线程的中断状态。

线程被通知中断后,中断状态设为true,当时被中断线程如何处理,视自己而定,可以再合适的时候响应中断,也可以完全不处理。

如下,线程自己判断中断状态来跳出循环

    @Test
    public void test() throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (; ; ) {
                System.out.println(System.currentTimeMillis());
                if (Thread.currentThread().interrupted()) {
                    return;
                }
            }
        });
        thread.start();
        thread.interrupt();
        thread.join();
    }
Last Updated:
Contributors: himcs