JAVA线程的生命周期

114 阅读3分钟


在了解JAVA线程的生命周期之前,先了解一下通用的线程生命周期

因为线程是操作系统里的一个概念,各种编程语言对其进行了不同的封装,但是对于线程的生命周期这部分,基本上是雷同的,只要了解了通用的线程生命周期模型,对于 Java 中线程的生命周期会容易理解的多,对于其它语言的线程生命周期亦是如此

通用的线程生命周期

通用的线程生命周期基本上可以用下图这个“五态模型”来描述。这五态分别是:初始状态、可运行状态、运行状态、休眠状态终止状态

  1. 初始状态,指的是线程已经被创建,但是还不允许分配 CPU 执行。这个状态属于编程语言特有的,不过这里所谓的被创建,仅仅是在编程语言层面被创建,而在操作系统层面,真正的线程还没有创建。
  2. 可运行状态,指的是线程可以分配 CPU 执行。在这种状态下,真正的操作系统线程已经被成功创建了,所以可以分配 CPU 执行。
  3. 当有空闲的 CPU 时,操作系统会将其分配给一个处于可运行状态的线程,被分配到 CPU 的线程的状态就转换成了运行状态
  4. 运行状态的线程如果调用一个阻塞的 API(例如以阻塞方式读文件)或者等待某个事件(例如条件变量),那么线程的状态就会转换到休眠状态,同时释放 CPU 使用权,休眠状态的线程永远没有机会获得 CPU 使用权。当等待的事件出现了,线程就会从休眠状态转换到可运行状态。
  5. 线程执行完或者出现异常就会进入终止状态,终止状态的线程不会切换到其他任何状态,进入终止状态也就意味着线程的生命周期结束了。

Java 中线程的生命周期

Java 语言中线程状态,分别是:

  1. NEW(初始化状态)
  2. RUNNABLE(可运行 / 运行状态)
  3. BLOCKED(阻塞状态)
  4. TERMINATED(终止状态)
一、NEW(初始化状态)状态

刚创建出来的线程就是NEW状态,NEW 状态的线程,不会被操作系统调度,因此不会执行。

Thread thread = new Thread(()->{});
二、NEW(初始化状态)到RUNNABLE(可运行 / 运行状态)状态

Java 线程要执行,就必须转换到 RUNNABLE 状态。从 NEW 状态转换到 RUNNABLE 状态很简单,只要调用线程对象的 start() 方法就可以了,示例代码如下:

Thread thread = new Thread(()->{});
thread.start();
三、RUNNABLE(可运行 / 运行状态)到 BLOCKED(阻塞状态)

在被调用sleep()、wait()、join()方法时会转换到阻塞状态,具体如下

  • sleep(long millis)方法:进入阻塞状态,在millis毫秒后唤醒,继续执行;
  • wait(long timeoutMillis)方法,和 sleep() 的不同之处在于,是不占用资源的,限制等待多久;
  • join()方法,待此线程执行完成后,再执行其他线程参考Thread.join源码分析
  • 有些 IO 阻塞,比如 write() 或者 read() ,因为IO方法是通过操作系统调用的。
Thread thread = new Thread(()->{});
thread.start();
​
thread.sleep(1000); // 线程休眠 1000毫秒后继续执行
thread.wait(1000); // 等待1000毫秒, 或者被调用 notify()或notifyAll()后才会被唤醒
thread.join(); // 合并线程, 待此线程执行完成后,再执行其他线程
四、RUNNABLE(可运行 / 运行状态)到TERMINATED(终止状态)
  • 线程执行完 run() 方法后,会自动转换到 TERMINATED 状态,
  • 如果执行 run() 方法的时候异常抛出,也会导致线程终止。
  • 如果需要强制中断 run() 方法的执行,可以调用 stop()destroy() 方法,不过已经标记为 @Deprecated,所以不建议使用了。正确的姿势其实是调用 interrupt() 方法。