为什么线程的sleep时间不准确?

在我们日常编程的过程中,经常会遇到一个问题:线程的sleep时间似乎并不像我们想象的那样准确,比如我们让线程sleep 100ms,实际sleep的时间经常是大于这个时间的。那么,为什么线程的sleep时间不准确呢?让我们来一探究竟。

线程状态:生命周期的五个阶段

首先我们需要了解一下线程的生命周期,线程的生命周期可以分为5个状态:

  1. 新生状态:线程对象被创建出来,但还没有开始运行。想象一下,这就像你买了一台新电脑,但还没有开机启动一样。
  2. 就绪状态:线程已经准备好运行,只是在等待系统分配CPU资源。这就像你已经打开了电脑,程序加载完毕,只等你开始操作一样。
  3. 运行状态:线程正在执行自己的代码,就像你正在使用电脑进行各种操作一样。
  4. 阻塞状态:线程暂时停止执行,等待某些条件满足后再继续运行。这就像你正在玩电脑游戏,突然有人打电话来,你需要暂停游戏去接电话一样。
  5. 死亡状态:线程执行完毕或被强制终止,就像你关闭电脑一样。

Sleep时间不准确的原因

休眠并非即刻醒来

当我们调用线程的sleep方法时,线程会进入阻塞状态,等待指定的时间后再恢复到就绪状态。然而,这个"恢复到就绪状态"并不意味着线程立即就会开始运行,它还需要等待系统分配CPU资源。因此,实际的sleep时间可能会超出我们设定的时间,这就是线程sleep时间不准确的主要原因。

上下文切换的额外消耗

此外,还有一些其他因素也会影响线程sleep的准确性,例如上下文切换的开销。每次线程切换,都需要保存当前线程的状态(例如寄存器的值、执行的地址空间等)并加载新线程的状态,这个过程是需要时间的。同时,CPU缓存中的数据也可能因为线程切换而失效,从而导致CPU需要从内存中重新读取数据,这也会增加额外的时间开销。

线程的调度:谁先运行

上面我们提到线程就绪后等待系统分配CPU资源是sleep时间超出的主要原因。那么,系统是如何决定哪个线程应该获得CPU资源的呢?这就涉及到了线程调度的问题。

线程调度是操作系统中的一项重要功能,其目标是使系统的运行尽可能高效。线程调度需要考虑的因素很多,包括用户需求(例如响应时间、周转时间等)、系统需求(例如吞吐量、CPU利用率等)、线程的优先级、资源平衡等。

在实际的线程调度中,往往需要在不同的需求之间做出权衡。例如,如果我们希望系统的响应时间尽可能小,那么就需要频繁地进行线程切换;但是,线程切换会带来额外的开销,从而降低系统的吞吐量和CPU利用率。这就像我们在玩游戏和接电话之间做出选择一样,无论我们选择哪一个,都需要牺牲另一个,而且选择之后还要想想刚才进行到哪里了。

如何做出决策

线程调度的时机通常在操作系统内核对中断/异常/系统调用处理后返回到用户态时。例如:

  • 当你正在使用文本编辑器写作时,突然移动了鼠标,操作系统就需要处理这个鼠标移动的中断,处理完毕后可能就会切换到其他线程,如音乐播放器线程。
  • 你的浏览器线程在运行过程中出现了异常,操作系统处理完异常后,可能会切换到其他正常运行的线程,如邮件客户端线程。
  • 你的下载线程请求读取硬盘文件,操作系统在处理完这个系统调用后,可能会切换到其他线程,如视频播放线程。

具体的调度算法根据操作系统的不同而不同,例如UNIX使用的是动态优先数算法,Linux使用的是抢占式算法(CFS完全公平调度算法),而Windows使用的是基于动态优先级的抢占式多任务调度。这些算法的细节这里就不赘述了,有兴趣的可以去查询一下。


总的来说,线程的sleep时间不准确主要是由于线程调度和上下文切换的开销导致的。在实际的编程中,我们需要意识到这一点,避免过度依赖sleep的准确性。

关注微/信/公/众/号:萤火架构,提升技术不迷路。

相关推荐
星栈13 分钟前
深度复盘:比 EventLoop 更隐蔽!Node 微任务堆积引发的线上接口雪崩事故
后端·node.js
名字还没想好☜1 小时前
Go slice 的 append 陷阱:共享底层数组导致的数据串改
开发语言·后端·golang·go·slice
诸神缄默不语1 小时前
FastAPI后端配置CORS中间件支持浏览器跨域访问
后端·fastapi
Fanta丶1 小时前
14.Activiti7 网关 排他网关ExclusiveGateway、并行网关ParallelGateway
后端
明月_清风1 小时前
robots.txt 完全指南:从入门到精通
后端·爬虫
jvmind_dev1 小时前
Java GC 实战指南(番外篇):被忽视的隐形杀手 —— Class Unloading 如何拖垮 GC
java·后端
可编程芯片开发1 小时前
基于MPPT最大功率跟踪的离网光伏发电系统Simulink建模与仿真
算法
明月_清风1 小时前
从零写一个"像人"的爬虫:反爬攻防实战指南
后端·爬虫
贰先生1 小时前
Xiuno BBS 审计之问题13:管理员发帖 doctype=0 时存储型 XSS
后端
AI科技星1 小时前
线性算子不是空间映射函数,是全域双螺旋场之间拉伸、旋转、耦合、坍缩的跨空间标准化变换载体《全域数学vs传统数学:人类文明进阶200讲》第80讲
线性代数·算法·矩阵·数据挖掘·回归·乖乖数学·全域数学