您好!欢迎来到源码码网!

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

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

在进行多线程开发之前,一定要先了解的就是线程的状态的各个状态的情况以及状态之间的转化。网上关于线程状态的说法大概有三个版本,实际上都没有太大的问题,因为有的是从操作系统上去对线程状态进行划分,而有的是根据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)
推荐阅读
  • 陀螺匠OA办公系统源码 PHP + Vue 前后端分离 完整可商用
  • 陀螺匠OA办公系统源码 PHP + Vue 前后端分离 完整可商用
  • 项目介绍《陀螺匠》是一套采用Laravel9框架结合Swoole高性能框架与Vue.js前端技术栈构建的AI+低代码双引擎智能办公系统。陀螺匠深度融合了AI智能体以及低代码开发平台,系统简约,易于功能扩展,方便二次开发。旨在为企业提供一站式、数智化转型的全方位解决方案,助力企业高效运营与智能决策。源码说明源码说明:项目代码100%开源,基于AGPL-3.0,支持免费商用!技术栈:系统基于Laravel9+Swoole+Vue.
  • 软件教程
  • 来源:CRMEB
  • 编辑:CRMEB
  • 时间:2026-03-27 15:33
  • 阅读:654
  • open claw最近很火,如何理性看待?
  • open claw最近很火,如何理性看待?
  • openclaw是2026年初科技圈最火爆的现象级话题。它不仅仅是又一个AI产品,更被百川智能的王小川誉为与ChatGPT诞生同等重要的里程碑——标志着AI从”只会说”的对话者,进化到了”能够做”的行动者。对于这股全民”养虾”热潮,我的观察是:它代表了一次人机关系的革命性跃迁,但同时也是一场充满风险与泡沫的狂欢,其真正的价值需要在喧嚣褪去、安全与成本的挑战被克服后才能显现。下
  • 行业资讯
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-03-17 11:06
  • 阅读:716
  • 原生小程序和封装的小程序有什么区别
  • 原生小程序和封装的小程序有什么区别
  • 原生小程序和封装的小程序是两种不同的开发模式,主要区别在于开发方式、性能表现、代码维护以及跨平台能力。为了让你更清晰地理解,我们可以把“原生”比作用钢筋水泥直接盖楼,而“封装”则是用预制板或套件来组装楼。以下是详细的对比分析:1.定义与本质原生小程序:定义: 直接使用微信官方提供的开发工具、语法和API进行开发。语言: 使用微信自己定义的一套技术栈(WXML(微信标记语言)做结构、WXSS(微信样式表)做样式、JS
  • 行业资讯
  • 来源:源码码网
  • 编辑:源码码网
  • 时间:2026-03-06 11:54
  • 阅读:944
  • 基于NetCore(Razor Page)开发的Cms建站系统MIT协议
  • 基于NetCore(Razor Page)开发的Cms建站系统MIT协议
  • FytSoaCms一款基于NetCore2.2/3.1(RazorPage)功能强大的Cms建站系统,支持前后端分离。简介:模块化:全新的架构和模块化的开发机制,便于灵活扩展和二次开发。模型/栏目/分类信息体系:通过栏目和模型绑定,以及不同的模型类型,不同栏目可以实现差异化的功能,轻松实现诸如资讯、下载、讨论和图片等功能。通过分类信息和栏目绑定,可以自动建立索引表,轻松实现复杂的信息检索。FytSoa是一套基于NetCore+SqlS
  • 开发工具
  • 来源:gitee
  • 编辑:源码码网
  • 时间:2026-01-24 22:21
  • 阅读:799
  • 基于JAVA开发的企业级平台微信公众号管理系统SmartWx
  • 基于JAVA开发的企业级平台微信公众号管理系统SmartWx
  • SmartWx微信公众号管理系统是一个完整的微信公众号web操作版,直接编译即可运行。让用户不再用关心微信的底层接口,直接使用页面进行操作,简单方便。包括服务器绑定、文本管理、图文管理、菜单管理、粉丝管理、群发消息等。技术框架开发语言:JAVA数据库:MYSQLJAVA开发框架:SpringMVC+Spring+Mybatis缓存框架:j2cache前端开发框架:Layui+JQuery+html前台模板引擎:art-templat
  • 源码教程
  • 来源:gitee
  • 编辑:源码码网
  • 时间:2026-01-24 21:53
  • 阅读:833
联系客服
源码代售 源码咨询 技术开发 联系客服
029-84538663
手机版

扫一扫进手机版
返回顶部