您好!欢迎来到源码码网

java中线程的状态以及状态转换

  • 行业资讯
  • 来源:源码码网
  • 编辑:admin
  • 时间:2020-05-14 16:50
  • 阅读:567

在进行多线程开发之前,一定要先了解的就是线程的状态的各个状态的情况以及状态之间的转化。网上关于线程状态的说法大概有三个版本,实际上都没有太大的问题,因为有的是从操作系统上去对线程状态进行划分,而有的是根据java源码来划分,所以会有一种情况就是你在这边看到线程有这几种状态,但是在另一边,则变成了另外的解释。并且,中间也有很多写的并不详细,也有一部分虽然没有大问题,但是中间混淆了概念。那么,这种情况下,看源码是最好的选择


java关于线程状态的源码

java中用了一个枚举类来表示线程的状态,分别是NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、TIMED_WAITING(定时等待)、WAITING(等待)、TERMINATED(终止、结束)。


附上源码:


 public enum State {

        /**

         * Thread state for a thread which has not yet started.

         */

        NEW,


        /**

         * Thread state for a runnable thread.  A thread in the runnable

         * state is executing in the Java virtual machine but it may

         * be waiting for other resources from the operating system

         * such as processor.

         */

        RUNNABLE,


        /**

         * Thread state for a thread blocked waiting for a monitor lock.

         * A thread in the blocked state is waiting for a monitor lock

         * to enter a synchronized block/method or

         * reenter a synchronized block/method after calling

         * {@link Object#wait() Object.wait}.

         */

        BLOCKED,


        /**

         * Thread state for a waiting thread.

         * A thread is in the waiting state due to calling one of the

         * following methods:

         * <ul>

         *   <li>{@link Object#wait() Object.wait} with no timeout</li>

         *   <li>{@link #join() Thread.join} with no timeout</li>

         *   <li>{@link LockSupport#park() LockSupport.park}</li>

         * </ul>

         *

         * <p>A thread in the waiting state is waiting for another thread to

         * perform a particular action.

         *

         * For example, a thread that has called <tt>Object.wait()</tt>

         * on an object is waiting for another thread to call

         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on

         * that object. A thread that has called <tt>Thread.join()</tt>

         * is waiting for a specified thread to terminate.

         */

        WAITING,


        /**

         * Thread state for a waiting thread with a specified waiting time.

         * A thread is in the timed waiting state due to calling one of

         * the following methods with a specified positive waiting time:

         * <ul>

         *   <li>{@link #sleep Thread.sleep}</li>

         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>

         *   <li>{@link #join(long) Thread.join} with timeout</li>

         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>

         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>

         * </ul>

         */

        TIMED_WAITING,


        /**

         * Thread state for a terminated thread.

         * The thread has completed execution.

         */

        TERMINATED;

    }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

初始状态(New)

用了new语句创建后但并未启动的线程就处于初始的状态,此时,和java其他所有的对象调用new语句一样,只是分配了内存,并对成员变量进行初始化,但是此时的线程对象并没有展示线程的任何动态特性;而从源码注释上也知道,官方对这个状态的定义是:尚未启动的线程的线程状态,这个状态基本没什么异议


就绪状态(操作系统的Ready状态)

线程处于初始状态,然后调用了线程的start方法,根据需要进行资源竞争,比如进入锁池中,参与锁的竞争;而在获得资源之后,并不能马上进入执行的状态,因为还需要时间片的分配;只有被线程调度器选中,分配了时间片,才能进入运行状态;而在一个线程获得锁之后,获得时间片之前,称为就绪状态(操作系统的Ready状态);但是,从java源码中可以看到并没有单独的就绪状态,需要注意的是,调用start方法之后默认的线程就进入就绪状态,JVM会为该线程创建方法并且调用堆栈程序计数器,往往start之后的线程并不会立即执行,但是其实通过对线程进行操作让它立刻执行,比如设置其睡眠一毫秒,这里关于start方法等待的内容稍后再说;此处还需要谨记的一点是,只能对处于新建状态的线程调用start方法,否则会报错!


运行状态(操作系统中的Running状态)

当线程处于Ready状态之后,此时所有处于此状态的线程存在于一个线程池中,等待CPU调度选中,分配时间片;当线程分配到时间片之后,线程占用cpu,执行程序代码,此时,线程便处于一个运行的状态,这就是操作系统中的Running状态。但是,java源码中并不存在单独的Running运行状态。


RUNNABLE状态(可运行)

其实很多人也会把操作系统的Ready状态叫做可运行状态,其实这个叫法也没问题。上面讲到,java中并没有单独的就绪状态和运行状态,取而代之的是一个叫做RUNNABLE的状态,在Java源码的注释中可以看到,官方对于RUNNABLE的定义是 :A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

意思是 处于runnable状态的线程在JVM中执行,但也可能处于一个等待操作系统其他资源例如处理器(时间片)的状态。所以其实这里的可运行状态包含了操作系统中的Ready状态和Running状态 联系上面的我们可以知道的一点就是,在java中,线程新建之后调用start方法,便进入了所谓的Runnable状态。


BLOCKED(阻塞状态)

BLOCKED我把它直译过来就是阻塞状态,其实这样并不严谨,操作系统上对于阻塞状态的定义是指线程因为某些原因放弃CPU,暂时停止运行,而被阻塞的线程也会在合适的机会重新进入就绪状态。在我看来,完整看完官方对于BLOCKED、WAITING和TIMED_WAITING,我感觉java中更像是将阻塞状态细分成了这三种(个人理解)。


这是官方对于阻塞状态的解释:A thread in the blocked state is waiting for a monitor lock

to enter a synchronized block/method or

reenter a synchronized block/method after calling

{@link Object#wait() Object.wait}.


大概意思是说等待获取一个对象锁(同步锁/也叫同步监视器)来进入一个同步块/同步方法,或者 调用了wait方法之后释放了本身所持有的锁然后想重新进入一个同步块/方法中。而操作系统上对于阻塞状态的定义是指线程因为某些原因放弃CPU,暂时停止运行,而被阻塞的线程也会在合适的机会重新进入就绪状态。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU。


这部分网上有人讲BLOCKED是锁池状态,把BLOCKED叫锁池其实有误导的成分,看了他们的关系转换图,其实有些是挺有问题的,很多人写着写着就和JVM的一些概念混在一起了,我个人觉得,从源码上来看,处于BLOCKED状态的核心是在等待接受一个监视器(排它锁)让它来进入同步块,从这来看倒是确实很像lock pool(这才是锁池)的概念,但是,java并不存在锁池状态的这样一个概念,锁池只是存放那些处于等待获取被其他线程占用了的对象的同步锁的线程的地方(有点拗口,好好断句会理解的吧),群殴自己理解就是存放那些处于BLOCKED状态的线程的地方;总之,从源码上来看,BLOCKED关键点在于 waiting for a monitor lock to enter a synchronized block


WAITING(无限期等待)

直接看源码:A thread is in the waiting state due to calling one of the following methods:

{@link Object#wait() Object.wait} with no timeout

{@link #join() Thread.join} with no timeout

{@link LockSupport#park() LockSupport.park}

A thread in the waiting state is waiting for another thread to

perform a particular action


大概意思是一个线程进行了以下三种操作中的一种就属于无限期等待状态,这三种操作分别是:


调用没有设置 Timeout 参数的 Object.wait() 方法

调用没有设置 Timeout 参数的 Thread.join() 方法

调用LockSupport.park() 方法;

并且,处于WAITING状态的线程会等待另一个线程进行特定操作才会退出WAITING状态。比如:


如果因为调用了wait方法造成了处于WAITING状态的话,那么等待另一个线程调用Object.notify() / Object.notifyAll()后便可以退出这种状态


如果是因为调用join方法,那么等待被调用的线程执行完毕即可退出


调用LockSupport.park()造成的则等待其他线程调用LockSupport.unpark(Thread)进行唤醒。


需要注意的是,处于无限期等待状态的线程,需要等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。


TIMED_WAITING(定时等待)

从源码可以知道,处于定时等待状态的原因可能是:


因为调用了Thread.sleep() 方法

可能是调用设置了 Timeout 参数的 Object.wait() 方法

可能是调用设置了 Timeout 参数的Thread.join() 方法

还有就是可能调用了LockSupport.parkNanos() 方法

调用了LockSupport.parkUntil() 方法

和WAITING状态不一样的是,限时等待无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。


而退出定时等待状态的方法与上面对应的分别是:


时间结束

时间结束或者调用 Object.notify() / Object.notifyAll()

时间结束 或者 被调用的线程执行完毕

调用LockSupport.unpark(Thread)

调用LockSupport.unpark(Thread)

上面也讲到,我个人理解的是JAVA把阻塞状态细化成了以上三种,而把这三种总结起来大概可以把造成阻塞状态的比较常见的原因分为:


线程试图调用一个同步监视器,但是这个监视器被其他线程持有

线程调用了阻塞IO方法,在该方法返回之前,这个线程都处于阻塞状态

线程调用sleep方法,放弃占有的处理器资源(需注意的点是和调用wait方法有区别,sleep是不会释放持有的锁,而wait会)

线程等待某种通知(notify/notifyAll)这里也有要注意的点,就是应用层线程实例尽量不要使用notifyall、notify和wait方法,这两个是object方法,他们是系统调用的,如果你在线程实例上使用这几个方法,可能不一定会按照你想要的结果来工作,这些之后再来详细讲

程序调用了线程的suspend()方法(线程挂起)这个也有需要注意的地方,suspeng()方法在源码中可以看到已经是过时方法,意思是不推荐使用,原因suspend()不会释放锁,如果在resume方法之前发生加锁行为,那么就会造成死锁的情况,出现线程被冻结的情况;这个也以后再细讲。

调用了join()方法,这个其实不应该单独成为一个原因,因为实质上调用join方法会判断当前执行的线程是否执行结束,执行线程如果结束,那么这个线程会调用notifyall方法,然后结束等待;实际上属于第4类,但是上面没讲到,就还是把它单独拿出来讲一下

上面这些是我对java线程阻塞的理解的总结,而且综合起来,会发现这个也比较符合操作系统中对于线程阻塞状态的定义。


TERMINATED(终止、结束、死亡)

对于这个,还是比较统一的,我也总结了线程结束的几种情况:


是线程结束任务之后正常结束,比如run()方法和call()方法执行正常完成之后正常死亡

抛出了一个未捕获的异常或者error而结束

直接调用了stop()方法,但是这个从源码中也可以看到这个不推荐使用,因为它很暴力,线程可能当时正在执行,此时直接调用stop方法,线程会释放所有的锁,可能会出现脏数据,破环数据一致性,并且很难发现(不会报错)

结束语

其实我之前并没打算单独写一篇这么长的文章来单独写这个,而且最近写了几篇学习总结,还没整理好,本来是打算先写好基础的总结,顺便写一下多线程开发中很多基础方法的介绍,对于线程状态的我是打算copy一下,然后一笔带过就够了,但是再进行学习的过程中,发现很多人可能和我一样的想法,并没深入研究或者研究了没详细解释也是直接一笔带过了,并且很多的还存在一些误解(我认为的),所以我还是决定花点时间来详细写一下这个,还差一张状态转换图,我之后再补上吧,当然,如果你觉得我所讲的有问题,欢迎评论纠正我,共同学习,一起进步!

————————————————


原文链接:https://blog.csdn.net/weixin_43390562/java/article/details/100754126


特别声明:
1、如无特殊说明,内容均为本站原创发布,转载请注明出处;
2、部分转载文章已注明出处,转载目的为学习和交流,如有侵犯,请联系客服删除;
3、编辑非《源码码网》的文章均由用户编辑发布,不代表本站立场,如涉及侵犯,请联系删除;
全部评论(0)
推荐阅读
  • 工程项目一体化自动管理软件解决方案
  • 工程项目一体化自动管理软件解决方案
  • 1.项目概述1.1项目背景在工程建设行业数字化转型浪潮下,传统项目管理面临信息孤岛、协同困难、进度不可控、成本超支等痛点。本方案旨在构建一个覆盖工程项目全生命周期、全参与方、全业务流程的一体化智能管理平台。1.2解决方案愿景打造数据驱动、智能协同、风险预警、自动执行的工程大脑,实现:管理流程自动化率≥80%项目协同效率提升40%成本偏差率降低至±3%以内安全事故发生率降低60%1.3目标用户矩阵┌───────────────┬
  • 行业资讯
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-01-09 11:26
  • 阅读:166
  • 车辆管理系统需求文档与技术架构PC端+小程序
  • 车辆管理系统需求文档与技术架构PC端+小程序
  • 第一部分:需求文档1.项目概述1.1项目背景为企事业单位、车队运营商、租赁公司等提供一套完整的车辆全生命周期管理解决方案,实现车辆管理数字化、智能化。1.2项目目标建立车辆从购置到报废的全流程管理体系实现用车申请、调度、监控、结算的闭环管理通过数据分析优化车辆使用效率降低车辆运维成本20%以上1.3用户角色矩阵┌──────────────┬─────────────────────────────┬──────────────
  • 行业资讯
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-01-09 11:11
  • 阅读:151
  • 智慧农业/渔业物联网系统需求文档
  • 智慧农业/渔业物联网系统需求文档
  • 智慧农业/渔业物联网系统需求文档文档版本: V1.0项目目标: 构建一个集环境智能监测、设备自动化控制、生长模型分析、溯源管理与远程指挥于一体的综合物联网管理平台,实现降本增效、提质增产、风险预警与品牌增值。1.系统总体概述1.1核心价值: 数据驱动决策,解放人力,实现农业/渔业生产的精准化、自动化与智能化。1.2用户角色:生产员/养殖员: 现场巡视、接收告警、执行设备手动控制、查看实时环境
  • 行业资讯
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-01-09 11:04
  • 阅读:65
  • 程序员AI编程工具推荐
  • 程序员AI编程工具推荐
  • AI编程工具是当前开发者的“副驾驶”,能够极大提升开发效率。以下我将从通用型、代码专用型、垂直领域型以及开源/自部署型几个维度为您分类推荐,并附上它们的核心特点和适用场景,帮助您选择。一、通用型AI对话助手(编程是核心能力之一)这类工具本质是“更懂代码的ChatGPT”,适合处理广泛的编程问题、解释代码、生成文档等。ChatGPT(GPT-4/4o)简介:行业标杆,尤其在GPT-4版本下,代码理解和生成能力极强。优点:上下文能力强,
  • 源码教程
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-01-09 10:56
  • 阅读:93
  • 中医考证在线学习小程序系统需求文档
  • 中医考证在线学习小程序系统需求文档
  • 中医考证在线学习小程序系统需求文档文档版本: V1.0目标用户: 中医执业医师、助理医师、确有专长、师承等考证学员核心价值: 利用移动化、碎片化、智能化工具,提升学习效率与考试通过率。1.项目概述1.1项目目标开发一款专为中医考证学员设计的微信小程序,提供从课程学习、题库练习、考点记忆、模考冲刺到学习社区的一站式闭环学习体验。旨在帮助学员充分利用碎片时间,系统化、高效地备考。1.2用户角色学员(主要用
  • 行业资讯
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-01-09 10:53
  • 阅读:29
联系客服
源码代售 源码咨询 技术开发 联系客服
029-84538663
手机版

扫一扫进手机版
返回顶部