0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

在Java中的线程状态转换

冬至子 来源:瑞煕share 作者:brevity wit 2023-06-02 10:07 次阅读

Java 中线程的生命周期中一共有 6 种状态。New(新创建);Runnable(可运行);Blocked(被阻塞);Waiting(等待);Timed Waiting(计时等待);Terminated(被终止)。如果想要确定线程当前的状态,可以通过 getState() 方法,并且线程在任何时刻只可能处于 1 种状态。

New 新创建

图片

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

Runnable 可运行

图片

Java 中的 Runable 状态对应操作系统线程状态中的两种状态,分别是 Running 和 Ready,也就是说,Java 中处于 Runnable 状态的线程有可能正在执行,也有可能没有正在执行,正在等待被分配 CPU 资源。所以,如果一个正在运行的线程是 Runnable 状态,当它运行到任务的一半时,执行该线程的 CPU 被调度去做其他事情,导致该线程暂时不运行,它的状态依然不变,还是 Runnable,因为它有可能随时被调度回来继续执行任务。

图片

接下来,我们来看下 Runnable 下面的三个方框,它们统称为阻塞状态,在 Java 中阻塞状态通常不仅仅是 Blocked,实际上它包括三种状态,分别是 Blocked(被阻塞)、Waiting(等待)、Timed Waiting(计时等待),这三 种状态统称为阻塞状态,下面我们来看看这三种状态具体是什么含义。

Blocked 被阻塞

图片

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

Waiting 等待

图片

我们再看看 Waiting 状态,线程进入 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() 。

Timed Waiting 限期等待

图片

在 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) 方法。

我们再来看下如何从这三种状态流转到下一个状态。

图片

想要从 Blocked 状态进入 Runnable 状态,要求线程获取 monitor 锁,而从 Waiting 状态流转到其他状态则比较特殊,因为首先 Waiting 是不限时的,也就是说无论过了多长时间它都不会主动恢复。

图片

只有当执行了 LockSupport.unpark(),或者 join 的线程运行结束,或者被中断时才可以进入 Runnable 状态。

图片

如果其他线程调用 notify() 或 notifyAll()来唤醒它,它会直接进入 Blocked 状态,这是为什么呢?因为唤醒 Waiting 线程的线程如果调用 notify() 或 notifyAll(),要求必须首先持有该 monitor 锁,所以处于 Waiting 状态的线程被唤醒时拿不到该锁,就会进入 Blocked 状态,直到执行了 notify()/notifyAll() 的唤醒它的线程执行完毕并释放 monitor 锁,才可能轮到它去抢夺这把锁,如果它能抢到,就会从 Blocked 状态回到 Runnable 状态。

图片

同样在 Timed Waiting 中执行 notify() 和 notifyAll() 也是一样的道理,它们会先进入 Blocked 状态,然后抢夺锁成功后,再回到 Runnable 状态。

图片

当然对于 Timed Waiting 而言,如果它的超时时间到了且能直接获取到锁/join的线程运行结束/被中断/调用了LockSupport.unpark(),会直接恢复到 Runnable 状态,而无需经历 Blocked 状态。

Terminated 终止

图片

再来看看最后一种状态,Terminated 终止状态,要想进入这个状态有两种可能。run() 方法执行完毕,线程正常退出。出现一个没有捕获的异常,终止了 run() 方法,最终导致意外终止。

注意点

最后我们再看线程转换的两个注意点。线程的状态是需要按照箭头方向来走的,比如线程从 New 状态是不可以直接进入 Blocked 状态的,它需要先经历 Runnable 状态。线程生命周期不可逆:一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变化。所以一个线程只能有一次 New 和 Terminated 状态,只有处于中间状态才可以相互转换。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102994
  • JAVA语言
    +关注

    关注

    0

    文章

    138

    浏览量

    19944
收藏 人收藏

    评论

    相关推荐

    Java线程的用法

    本文将介绍一下Java线程的用法。 基础介绍 什么是多线程 指的是在一个进程中同时运行多个线程,每个线程都可以独立执行不同的任务或操作。
    的头像 发表于 09-30 17:07 622次阅读

    Java中的线程池包括哪些

    线程池是用来统一管理线程的,在 Java 中创建和销毁线程都是一件消耗资源的事情,线程池可以重复使用线程
    的头像 发表于 10-11 15:33 564次阅读
    <b class='flag-5'>Java</b>中的<b class='flag-5'>线程</b>池包括哪些

    线程的分离状态 pthread

    系统资源。程序员应该根据自己的需要,选择适当的分离状态。所以如果我们创建线程时就知道不需要了解线程的终止状态,则可以pthread_att
    发表于 09-26 09:36

    Java线程阻塞方法大全

    IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。以下是详细的唤醒方法:1. sleep() 方法sleep(毫秒),指定以毫秒为单位的时间,使线程该时间内进入线程阻塞
    发表于 04-02 15:42

    Java线程唤醒与阻塞规则

    IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。以下是详细的唤醒方法:1. sleep() 方法:sleep(毫秒),指定以毫秒为单位的时间,使线程该时间内进入线程
    发表于 07-06 15:11

    Java线程的五种状态

    java线程的五种状态其实要真正高清,只需要明白计算机操作系统中进程的知识,原理都是相同的。
    发表于 08-02 07:59

    Java守护线程和本地线程的区别

    java线程分为两种:守护线程(Daemon)和用户线程(User)。
    发表于 08-07 08:10

    java线程设计模式_结城浩

    JAVA线程设计模式》通过浅显易懂的文字与实例来介绍JAVA线程相关的设计模式概念,并且通过实际的JAVA程序范例和UML图示来一一解说
    发表于 01-05 16:15 0次下载
    <b class='flag-5'>java</b>多<b class='flag-5'>线程</b>设计模式_结城浩

    java线程状态图和定义

    线程时由系统分配的,主要用来保存线程内部所使用的数据,如线程执行函数中所定义的变量。 注意:Java中的多线程是一种抢占机制而不是分时机制
    发表于 09-27 10:44 0次下载
    <b class='flag-5'>java</b><b class='flag-5'>线程</b>的<b class='flag-5'>状态</b>图和定义

    java学习——java面试【事务、锁、多线程】资料整理

    本文档内容介绍了基于java学习java面试【事务、锁、多线程】资料整理,供参考
    发表于 03-13 13:53 0次下载

    java定时器和多线程

    完成一个java application应用程序,在应用程序主进程中新开一个线程,此线程进行死循环,每1秒被激活一次,激活时即在输出显示当前时间。
    发表于 06-17 14:11 2607次阅读
    <b class='flag-5'>java</b>定时器和多<b class='flag-5'>线程</b>

    Java线程学习基础详解

    使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程
    的头像 发表于 12-10 22:02 244次阅读

    为什么Java线程没有Running状态

    什么是 RUNNABLE? 与传统的ready状态的区别 与传统的running状态的区别 当I/O阻塞时 如何看待RUNNABLE状态Java虚拟机层面所暴露给我们的
    的头像 发表于 06-17 17:36 1270次阅读

    Java线程池核心原理

    看过Java线程池源码的小伙伴都知道,在Java线程池中最核心的类就是ThreadPoolExecutor,
    的头像 发表于 04-21 10:24 617次阅读

    java实现多线程的几种方式

    Java实现多线程的几种方式 多线程是指程序中包含了两个或以上的线程,每个线程都可以并行执行不同的任务或操作。
    的头像 发表于 03-14 16:55 176次阅读