Thread —— 线程生命周期|8月更文挑战

184 阅读3分钟

这是我参与8月更文挑战的第9天,活动详情查看:8月更文挑战

就像生物从出生到长大、最终死亡的过程一样,线程也有自己的生命周期,在 Java 中线程的生命周期中一共有 6 种状态。

  • New(新创建)
  • Runnable(可运行)
  • Blocked(被阻塞)
  • Waiting(等待)
  • Timed Waiting(计时等待)
  • Terminated(被终止)

如果想要确定线程当前的状态,可以通过 getState() 方法,并且线程在任何时刻只可能处于 1 种状态。线程状态切换:

线程状态切换.jpg

1 新建状态(NEW)

Thread-NEW.png

New 表示线程被创建但尚未启动的状态:当我们用 new Thread() 新建一个线程时,如果线程没有开始运行 start() 方法,所以也没有开始执行 run() 方法里面的代码,那么此时它的状态就是 New。而一旦线程调用了 start(),它的状态就会从 New 变成 Runnable,也就是状态转换图中中间的这个大方框里的内容。

2 可运行状态(RUNNABLE)

Thread-RUNNABLE.png

Java 中的 Runable 状态对应操作系统线程状态中的两种状态,分别是 Running 和 Ready,也就是说,Java 中处于 Runnable 状态的线程有可能正在执行,也有可能没有正在执行,正在等待被分配 CPU 资源。

所以,如果一个正在运行的线程是 Runnable 状态,当它运行到任务的一半时,执行该线程的 CPU 被调度去做其他事情,导致该线程暂时不运行,它的状态依然不变,还是 Runnable,因为它有可能随时被调度回来继续执行任务。

3 被阻塞状态(BLOCKED)

Thread-BLOCKED.png

首先来看最简单的 Blocked,从箭头的流转方向可以看出,从 Runnable 状态进入 Blocked 状态只有一种可能,就是进入 synchronized 保护的代码时没有抢到 monitor 锁,无论是进入 synchronized 代码块,还是 synchronized 方法,都是一样。当处于 Blocked 的线程抢到 monitor 锁,就会从 Blocked 状态回到Runnable 状态。

4 等待状态(WAITING)

Thread-WAITING.png

线程进入 Waiting 状态有三种可能性:

  • 没有设置 Timeout 参数的 Object.wait() 方法
  • 没有设置 Timeout 参数的 Thread.join() 方法
  • LockSupport.park() 方法

Blocked 仅仅针对 synchronized monitor 锁,可是在 Java 中还有很多其他的锁,比如 ReentrantLock,如果线程在获取这种锁时没有抢到该锁就会进入 Waiting 状态,因为本质上它执行了 LockSupport.park() 方法,所以会进入 Waiting 状态。同样,Object.wait() 和 Thread.join() 也会让线程进入 Waiting 状态。

Blocked 与 Waiting 的区别是 Blocked 在等待其他线程释放 monitor 锁,而 Waiting 则是在等待某个条件,比如 join 的线程执行完毕,或者是 notify()/notifyAll() 。

5 计时等待状态(TIMED_WAITING)

Thread-TIMED_WAITING.png

在 Waiting 上面是 Timed Waiting 状态,这两个状态是非常相似的,区别仅在于有没有时间限制,Timed Waiting 会等待超时,由系统自动唤醒,或者在超时前被唤醒信号唤醒。以下情况会让线程进入 Timed Waiting 状态。

  • 设置了时间参数的 Thread.sleep(long millis) 方法
  • 设置了时间参数的 Object.wait(long timeout) 方法
  • 设置了时间参数的 Thread.join(long millis) 方法
  • 设置了时间参数的 LockSupport.parkNanos(long nanos) 方法和 LockSupport.parkUntil(long deadline) 方法

6 已终止状态(TERMINATED)

Thread-TERMINATED.png

线程会以下面三种方式结束,结束后就是终止状态:

  • 正常结束:run()或 call()方法执行完成,线程正常结束
  • 异常结束:线程抛出一个未捕获的 Exception 或 Error
  • 调用 stop:直接调用该线程的 stop()方法来结束该线程—该方法通常容易导致死锁,不推荐使用