为什么线程的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的准确性。

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

相关推荐
techdashen20 分钟前
Arborium:把 tree-sitter 语法高亮打包成 Rust 文档生态的基础设施
开发语言·后端·rust
mingo_敏23 分钟前
Mean-Teacher 均值教师自训练框架详解
算法·均值算法
Profile排查笔记35 分钟前
指纹浏览器环境异常排查:Fingerprint、Profile、Proxy、Session 和 Task Log 怎么看
前端·人工智能·后端·自动化
小强库计算机毕业设计39 分钟前
源码分享Spring Boot + Vue3 的校园社团管理系统
java·spring boot·后端·计算机毕业设计
星空露珠1 小时前
迷你世界UGc3.0脚本Wiki[剧情动画模块管理接口 Timeline]
开发语言·数据结构·算法·游戏·lua
笨笨没好名字1 小时前
Leetcode刷题python3版第一周(下)
linux·算法·leetcode
手写码匠1 小时前
手写 LLM 安全护栏:从内容审核到越狱防御的完整实现
人工智能·深度学习·算法·aigc
luj_17681 小时前
草酸与烟酸对消化及糖代谢的影响解析
服务器·c语言·开发语言·经验分享·算法
阿新聊ai1 小时前
从 Prompt 到 Loop:AI 编程 Agent 四代循环的演进全景
人工智能·后端
im_lanny1 小时前
从 Function Calling 到 MCP:Agent 工具调用的三层境界与生产级安全护栏
后端