线程的生命周期详解

news/2024/5/19 1:08:04 标签: 多线程, 流程图

一个线程的生命周期有6个阶段:

  1. 新建,是刚使用new方法,new出来的线程;
  2. 就绪,是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段;
  3. 运行,当就绪的线程被调度并获得CPU资源时,便进入运行状态;
  4. 阻塞,在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态;
  5. 等待,线程进入等待状态是因为调用了wait()方法或者join()方法;
  6. 死亡,线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁。

线程的生命周期包含6个阶段,包括:新建、就绪、运行、阻塞、等待、死亡(销毁)。完整的生命周期图如下:

当线程进入运行状态后,一般的操作系统是采用抢占式的方式来让线程获得CPU。所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞、就绪之间切换。

1、新建(new)

使用new方法,new出来线程,此时仅仅由JAVA虚拟机为其分配内存,并初始化成员变量的值。此时仅仅是个对象。

2、就绪(runnable)

就是调用的线程的start()方法后,这时候线程处于等待CPU分配资源阶段,谁先抢的CPU资源,谁开始执行;
该线程进入就绪状态,JAVA虚拟机会为其创建方法调用栈和程序计数器。线程的执行是由底层平台控制, 具有一定的随机性。

3、运行(running)

当就绪的线程被调度并获得CPU资源时,便进入运行状态,run方法定义了线程的操作和功能;(当处于就绪状态的线程获得CPU,它就会执行run()方法)
对于一个单核cpu(或者是一个内核)来说,只能同时执行一条指令,而JVM通过快速切换线程执行指令来达到多线程的,真正处理器就能同时处理一条指令,只是这种切换速度很快,我们根本不会感知到。为了线程切换后能恢复到正确的执行位置,每条线程都有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储。
当一个线程开始运行后,它不可能一直持有CPU(除非该线程执行体非常短,瞬间就执行结束了)。所以,线程在执行过程中需要被中断,目的是让其它线程获得执行的CPU的机会。线程的调度细节取决于底层平台所采用的策略。

4、阻塞(blocked)

处于运行中的线程,由于某种原因放弃对cpu的使用权,处于阻塞状态,直到其进入就绪状态,才有机会再次被cpu调用进入运行状态。

根据阻塞原因不同,阻塞分为三种

  • 等待阻塞:运行状态中的线程执行wait方法,进入等待队列,等待阻塞;Java虚拟机就会把线程放到这个对象的等待池中

  • 同步阻塞:线程获取同步锁失败(因为锁被其他线程占用),Java虚拟机就会把这个线程放到这个对象的锁池中

  • 其他阻塞:通过调用sleep方法或者join方法或者发出I/O请求时,线程会进入阻塞状态,当sleep()状态超时,或者join()等待线程终止或者超时,或者I/O处理完毕,线程重新转入就绪状态

5、等待(Waiting)

线程进入等待状态是因为调用了wait()方法或者join()方法。在等待状态下,线程会暂停执行,直到其他线程调用notify()或者notifyAll()方法来唤醒它。 

对于 Waiting 状态的进入有三种情况,分别为:

  • 当线程中调用了没有设置 Timeout 参数的 Object.wait() 方法
  • 当线程调用了没有设置 Timeout 参数的 Thread.join() 方法
  • 当线程调用了 LockSupport.park() 方法

定时等待状态(TIMED_WAITING)

  将运行状态中的线程转换为定时等待状态中的线程与转换为等待状态中的线程操作类似,只是运行线程调用了有时间参数限制的方法,如sleep(long millis)、wait(long timeout)、join(long millis)等方法。

  处于定时等待状态中的线程也不能立即争夺CPU使用权,必须等待其他相关线程执行完特定的操作或者限时时间结束后,才有机会再次争夺CPU使用权,将定时等待状态的线程转换为运行状态。例如,调用了wait(long timeout) 方法而处于等待状态中的线程,需要通过其他线程调用notify()或者notifyAll()方法唤醒当前等待中的线程,或者等待限时时间结束后也可以进行状态转换。

6、销毁(terminated)

如果线程正常执行完毕后或线程被提前强制性的终止或出现异常导致结束,那么线程就要被销毁,释放资源。

  1. run()、call()方法执行完成,线程正常结束
  2. 线程抛出一个未捕获的Exception或Error
  3. 直接调用线程的stop()方法结束该线程——该方法容易导致死锁,通常不建议使用

线程状态转换图 

总结

最后我们说一下再看线程转换的过程中一定要注意两点:

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

http://www.niftyadmin.cn/n/4975498.html

相关文章

系统架构设计高级技能 · Web架构

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in reality. 点击进入系列文章目录 系统架构设计高级技能 Web架构 一、Web架构介绍1.1 Web架构涉及技术1.2 单台服务…

配置Maxwell

配置Maxwell_1.29.2 1.安装Maxwell2. 配置MySQL 链接: maxwells官网 1.安装Maxwell 2)将安装包解压至/opt/module tar -zxvf maxwell-1.29.2.tar.gz -C /opt/module/3)修改名称 mv maxwell-1.29.2/ maxwell2. 配置MySQL 3.2.1 启用MySQL Binlog MySQL服…

AI 插件:未来的浏览器、前端与交互

想象一下,你在浏览器中粘贴一个 URL,这个 URL 不仅仅是一个网址,而是一个功能强大、能执行多种任务的 AI 插件。这听起来像是未来的事情,但实际上,这种变革已经悄悄进行中。 1. 插件的魅力与局限性 当我第一次接触到…

Pyecharts教程(四):使用pyecharts绘制3D折线图

Pyecharts教程(四):使用pyecharts绘制3D折线图 作者:安静到无声 个人主页 目录 Pyecharts教程(四):使用pyecharts绘制3D折线图准备工作数据准备绘制3D折线图推荐专栏在这篇文章中,我们将学习如何使用pyecharts库来绘制一个3D折线图。pyecharts是一个用于生成Echarts图表的…

土豆叶病害识别(图像连续识别和视频识别)

效果视频:土豆叶病害识别(Python代码,pyTorch框架,视频识别)_哔哩哔哩_bilibili 代码运行要求:Torch库>1.13.1,其它库无版本要求 1..土豆叶数据集主要包好三种类别(Early_Blight…

第三讲,三维空间刚体运动

一个刚体在三维空间中的运动是如何描述的。我们当然知道这由一次旋转加一次平移组成。平移确实没有太大问题,但旋转的处理是件麻烦事。我们将介绍旋转矩阵、四 元数、欧拉角的意义,以及它们是如何运算和转换的。 1.向量,坐标系和旋转矩阵 点…

Unity音频基础概念

一、音源与音频侦听器 游戏画面能够被观众看到,是因为有渲染器和摄像机,同样音频能够被听到,也要有声音的发出者与声音的接收者。声音的发出者叫做音源,接收者叫做音频侦听器。Audio Source与Audio Listener都是组件,…

JS 常见的 6 种继承方式

原型链继承 原型链继承是比较常见的继承方式之一,其中涉及的构造函数、原型和实例,三者之间存在着一定的关系,即每一个构造函数都有一个原型对象,原型对象又包含一个指向构造函数的指针,而实例则包含一个原型对象的指…