美文网首页
Java 线程的状态及状态转换

Java 线程的状态及状态转换

作者: cbhe | 来源:发表于2020-06-20 01:00 被阅读0次

通用的线程周期

操作系统中,线程的状态一般包含以下五种:初始状态可运行状态运行状态休眠状态终止状态

通用的线程状态转换图--五态模型
  1. 初始状态:指的是线程已经被创建但还不允许分配CPU资源。这个状态是编程语言特有的,而且这里的“创建”也是指编程语言层面的被创建,实际上并没有在操作系统层面上创建线程。
  2. 可运行状态:在这个状态下线程可以分配CPU资源,而且真正的操作系统级别的线程已经被创建,线程一旦分配到CPU资源就会立即运行。
  3. 运行状态:当有空闲CPU资源时,操作系统会挑选一个处于可运行状态的线程并为其分配CPU资源,被挑选出来分配到CPU资源的线程就会进入运行状态。
  4. 休眠状态:当运行状态的线程调用一个阻塞API或者等待某个事件时,那么它的状态就会从运行状态转换为休眠状态。处于休眠状态的线程永远不会分配到CPU资源。当等待的事件出现时,休眠状态的线程就会转换到可运行状态。
  5. 终止状态:线程运行完成或者出现异常时就会进入终止状态,终止状态的线程不会再转变成其他状态。线程进入终止状态意味着生命周期的结束。

Java 中线程的声明周期

Java 中的线程一共有6个状态:

  1. NEW(新建)
  2. RUNNABLE(可运行/运行)
  3. BLOCKED(阻塞)
  4. WAITING(无限时等待)
  5. TIMED_WAITING(有限时等待)
  6. TERMINATED(终止)

看上去很复杂,但其实 blocked、waiting、timed_waiting 这三种状态对应的都是操作系统中的同一种状态 ---- 休眠状态。
所以,Java 线程的声明周期可以简化为下图:


Java 线程的状态转换图

它们之间的转换关系是什么样的呢,我们来分析一下:

1.NEW → RUNNABLE

NEW 状态在 Java 语言中对应于调用start()方法之前的Thread的实例。所以从 NEW 到 RUNNABLE 的转换很简单就是调用一下start()方法。

2.RUNNABLE ⇌ BLOCKED

只有一种情况会让线程从RUNNABLE 状态转换为 BLOCKED 状态,就是线程等待 synchronized 隐式锁。synchronized 关键字修饰的代码块、方法在同一时刻只允许一个线程执行,其他线程只能等待,等待的线程就会从 RUNNABLE 状态转换成 BLOCKED 状态。而当线程获取到隐式锁时就会从 BLOCKED 状态转换成 RUNNABLE 状态。
应当注意的是:当线程调用阻塞API时,在操作系统层面上看,线程会进入休眠态,但是在Java层面上看,此时这个Java线程依然是RUNNABLE 状态。

3.RUNNABLE ⇌ WAITING

有三种情况会触发 RUNNABLE 和 WAITING 之间的转换:

  • 场景一:在 synchronized 代码块中调用 object.wait() 方法
  • 场景二:处于 RUNNABLE 状态的线程调用thread.join()方法等待某个线程运行完成。例如thread1中有一行代码是thread2.join()则执行这行代码后thread1会从RUNNABLE 状态转换成 WAITING 状态,直到thread2执行完成以后,thread1才会从 WAITING 状态再次回到 RUNNABLE 状态。
  • 场景三:调用LockSupport.park()方法,会让当前线程从RUNNABLE 转换为 WAITING。当某个线程调用了LockSupport.unpark(thread)时,thread方法就会从WAITING状态转换成RUNNABLE状态。
4.RUNNABLE ⇌ TIMED_WAITING

有四种场景可以使得线程从 RUNNABLE 状态转换到 TIMED_WAITING 状态:

  • 场景一:Object.wait(long timeout)
  • 场景二:Thread.join(long timeout)
  • 场景三:LockSupport.parkUntil(long deadline) (还有一个park型方法,这里不列举了)
  • 场景四:Thread.sleep(long timeout)

可以看出,这四种场景的前三种都是上面提到的函数的带时间参数的形式,最后一个是我们最直接可以想到的sleep。

5.RUNNABLE → TERMINATED

线程执行完 run() 方法后就会自动进入 TERMINATED 状态,如果抛出异常的话也会进入到这个状态。有时候,我们需要强行停止 run() 方法的运行,这时候我们只需要调用线程的 interrupt() 方法即可让线程直接进入 TERMINATED 状态。
应当注意的是,Java 还提供了Thread.stop()方法强制停止线程,但这个方法非常残暴,它使得线程直接停止而无法执行后续必要操作,比如无法释放已经获取的锁。而interrupt就比较温和,它只是通知一下线程应当停止了,而线程什么时候停止则取决于线程本身。如果线程处于WAITING、TIMED_WAITING时,那么interrupt则会唤醒线程,让其重新进入 RUNNABLE 状态然后抛出 InterruptedException 异常。如果线程处于 RUNNABLE 状态,则线程会在合适的时候检测一下自己是否被需要中断,如果需要中断则首先需要做一些必要的操作,然后再进入 TERMINATED 状态。

相关文章

  • JAVA多线程及线程状态转换

    Java多线程及线程状态转换 - 祖华 - 博客园

  • Java 线程的七种状态

    本篇感性地介绍一下 Java 线程的七种状态以及状态之间的转换 Java 线程状态转换图 Java 线程状态 在 ...

  • Java 线程的状态及状态转换

    通用的线程周期 操作系统中,线程的状态一般包含以下五种:初始状态、可运行状态、运行状态、休眠状态、终止状态 初始状...

  • java线程状态及转换

    java线程状态:new(新建),runnable(就绪),running(运行),blocked(阻塞),dea...

  • Java线程状态及其转换

    线程状态及其转换 一、线程状态 Java中定义线程的状态有6种,可以查看Thread类的State枚举: 初始(N...

  • Java线程状态转换

    线程状态类型 在java.long.Thread类的内部定义了一个枚举 新建状态(NEW) 就绪状态(RUNNAB...

  • 线程的状态及转换

    上篇简单介绍了synchronized关键字的使用,多个线程并发操作一个共享变量时,当一个线程获得对象锁,其余线程...

  • JAVA线程生命周期

    JAVA线程生命周期 摘要 本文详细总结了java线程的五种基本状态,和状态之间的转换关系;介绍了常见了创建线程的...

  • 面试小结之并发篇

    最近面试一些公司,被问到的关于Java并发编程的问题,以及自己总结的回答。 Java线程的状态及如何转换。 多个线...

  • 2018-11-11

    如何新建一个线程? 线程状态是怎样转换的? 关于线程状态的操作是怎样的? 1. 新建线程 一个java程序从mai...

网友评论

      本文标题:Java 线程的状态及状态转换

      本文链接:https://www.haomeiwen.com/subject/ppxixktx.html