大神的代码里看到个 Thread.Sleep(0),写的bug?

Java中的线程休眠大法系列(一)Thread.sleep() 文章目录前言Thread.sleep()1.看看JDK中此方法上面的注释2.案例展示(线程状态:TIMED_WAITING)3.案例展示(InterruptedException异常会清除interrupted status)4.案例展示(sleep不会释放monitors锁)总结 前言 如果让一个线程进入休眠? 我们第一个想到的就是Thread.sleep(long millis)方法吧! 如果你对synchronized足够了解的话,那么你肯定还能想到Object.wait()方法。 再如果你对jav 阅读详情

95f7aef69d8da0837c7fdfe0e97326d2.png

前 言

我们可能经常会用到 Thread.Sleep 函数来把使线程挂起一段时间。那么你有没有正确的理解这个函数的用法呢?

思考下面这两个问题:

①、假设现在是 2022-01-01 00:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2022-01-01 00:00:01.000 的时候,这个线程会不会被唤醒?

②、某人的代码中用了一句看似莫明其妙的话:Thread.Sleep(0) 。既然是 Sleep 0 毫秒,那么他跟去掉这句代码相比,有啥区别么?

回顾操作系统原理

我们先回顾一下操作系统原理。

操作系统中,CPU竞争有很多种策略。Unix系统使用的是时间片算法,而Windows则属于抢占式的。

在时间片算法中,所有的进程排成一个队列。操作系统按照他们的顺序,给每个进程分配一段时间,即该进程允许运行的时间。如果在时间片结束时进程还在运行,则CPU将被剥夺并分配给另一个进程。

如果进程在时间片结束前阻塞或结束,则CPU当即进行切换。调度程 序所要做的就是维护一张就绪进程列表,当进程用完它的时间片后,它被移到队列的末尾。

所谓抢占式操作系统,就是说如果一个进程得到了 CPU 时间,除非它自己放弃使用 CPU ,否则将完全霸占 CPU 。因此可以看出,在抢占式操作系统中,操作系统假设所有的进程都是“人品很好”的,会主动退出 CPU 。

在抢占式操作系统中,假设有若干进程,操作系统会根据他们的优先级、饥饿时间(已经多长时间没有使用过 CPU 了),给他们算出一个总的优先级来。操作系统就会把 CPU 交给总优先级最高的这个进程。

当进程执行完毕或者自己主动挂起后,操作系统就会重新计算一 次所有进程的总优先级,然后再挑一个优先级最高的把 CPU 控制权交给他。

我们用分蛋糕的场景来描述这两种算法。假设有源源不断的蛋糕(源源不断的时间),一副刀叉(一个CPU),10个等待吃蛋糕的人(10 个进程)。

如果是Unix操作系统来负责分蛋糕,那么他会这样定规矩:每个人上来吃 1 分钟,时间到了换下一个。最后一个人吃完了就再从头开始。于是,不管这10个人是不是优先级不同、饥饿程度不同、饭量不同,每个人上来的时候都可以吃 1 分钟。

当然,如果有人本来不太饿,或者饭量小,吃了30秒钟之后就吃饱了,那么他可以跟操作系统说:我已经吃饱了(挂起)。于是操作系统就会让下一个人接着来。

如果是 Windows 操作系统来负责分蛋糕的,那么场面就很有意思了。他会这样定规矩:我会根据你们的优先级、饥饿程度去给你们每个人计算一个优先级。优先级最高的那个人,可以上来吃蛋糕——吃到你不想吃为止。等这个人吃完了,我再重新根据优先级、饥饿程度来计算每个人的优先级,然后再分给优先级最高的那个人。

这样看来,这个场面就有意思了——可能有些人是漂亮MM,因此具有高优先级,于是她就可以经常来吃蛋糕。

可能另外一个人是个丑男,而且很ws,所以优先级特别低,于是好半天了才轮到他一次(因为随着时间的推移,他会越来越饥饿,因此算出来的总优先级就会越来越高,因此总有一天会轮到他的)。

而且,如果一不小心让一个大胖子得到了刀叉,因为他饭量大,可能他会霸占着蛋糕连续吃很久很久,导致旁边的人在那里咽口水。。。

而且,还可能会有这种情况出现:操作系统现在计算出来的结果,5号PPMM总优先级最高,而且高出别人一大截。因此就叫5号来吃蛋糕。5号吃了一小会儿,觉得没那么饿了,于是说“我不吃了”(挂起)。因此操作系统就会重新计算所有人的优先级。

因为5号刚刚吃过,因此她的饥饿程度变小了,于是总优先级变小了;而其他人因为多等了一会儿,饥饿程度都变大了,所以总优先级也变大了。

不过这时候仍然有可能5号的优先级比别的都高,只不过现在只比其他的高一点点——但她仍然是总优先级最高的啊。因此操作系统就会说:5号mm上来吃蛋糕……(5号mm心里郁闷,这不刚吃过嘛……人家要减肥……谁叫你长那么漂亮,获得了那么高的优先级)。

那么,Thread.Sleep 函数是干吗的呢?还用刚才的分蛋糕的场景来描述。

上面的场景里面,5号MM在吃了一次蛋糕之后,觉得已经有8分饱了,她觉得在未来的半个小时之内都不想再来吃蛋糕了,那么她就会跟操作系统说:在未来的半个小时之内不要再叫我上来吃蛋糕了。

这样,操作系统在随后的半个小时里面重新计算所有人总优先级的时候,就会忽略5号mm。Sleep函数就是干这事的,他告诉操作系统“在未来的多少毫秒内我不参与CPU竞争”

看完了 Thread.Sleep 的作用,我们再来想想文章开头的两个问题。

第一个问题

对于第一个问题,答案是:不一定。

因为你只是告诉操作系统:在未来的1000毫秒内我不想再参与到CPU竞争。那么1000毫秒过去之后,这时候也许另外一个线程正在使用CPU,那么这时候操作系统是不会重新分配CPU的,直到那个线程挂起或结束;况且,即使这个时候恰巧轮到操作系统进行CPU 分配,那么当前线程也不一定就是总优先级最高的那个,CPU还是可能被其他线程抢占去。

与此相似的,Thread有个Resume函数,是用来唤醒挂起的线程的。好像上面所说的一样,这个函数只是“告诉操作系统我从现在起开始参与CPU竞争了”,这个函数的调用并不能马上使得这个线程获得CPU控制权。

第二个问题

对于第二个问题,答案是:有,而且区别很明显。

假设我们刚才的分蛋糕场景里面,有另外一个PPMM 7号,她的优先级也非常非常高(因为非常非常漂亮),所以操作系统总是会叫道她来吃蛋糕。而且,7号也非常喜欢吃蛋糕,而且饭量也很大。

不过,7号人品很好,她很善良,她没吃几口就会想:如果现在有别人比我更需要吃蛋糕,那么我就让给他。因此,她可以每吃几口就跟操作系统说:我们来重新计算一下所有人的总优先级吧。

不过,操作系统不接受这个建议——因为操作系统不提供这个接口。于是7号mm就换了个说法:“在未来的0毫秒之内不要再叫我上来吃蛋糕了”。这个指令操作系统是接受的,于是此时操作系统就会重新计算大家的总优先级——注意这个时候是连7号一起计算的,因为“0毫秒已经过去了”嘛。

因此如果没有比7号更需要吃蛋糕的人出现,那么下一次7号还是会被叫上来吃蛋糕。

因此,Thread.Sleep(0)的作用,就是“触发操作系统立刻重新进行一次CPU竞争”。

竞争的结果也许是当前线程仍然获得CPU控制权,也许会换成别的线程获得CPU控制权。这也是我们在大循环里面经常会写一句Thread.Sleep(0) ,因为这样就给了其他线程比如Paint线程获得CPU控制权的权力,这样界面就不会假死在那里。

另外,虽然上面提到说“除非它自己放弃使用 CPU ,否则将完全霸占 CPU”,但这个行为仍然是受到制约的——操作系统会监控你霸占CPU的情况,如果发现某个线程长时间霸占CPU,会强制使这个线程挂起,因此在实际上不会出现“一个线程一直霸占着 CPU 不放”的情况。

至于我们的大循环造成程序假死,并不是因为这个线程一直在霸占着CPU。实际上在这段时间操作系统已经进行过多次CPU竞争了,只不过其他线程在获得CPU控制权之后很短时间内马上就退出了,于是就又轮到了这个线程继续执行循环,于是就又用了很久才被操作系统强制挂起...... 因此反应到界面上,看起来就好像这个线程一直在霸占着CPU一样。

time.sleep() 深度解析:精度、线程、asyncio 与生产级替代方案 time.sleep() 表面是 Python 基础暂停函数,实则是 Python 解释器、C 标准库与操作系统内核协同调度的关键接口。其行为由底层时钟源(如 nanosleep/Sleep)、线程模型(是否释放 GIL)及运行环境(同步/异步、GUI/服务)共同决定。理解 sleep 的不可中断性、平台精度差异(Windows 15ms vs Linux 1ms)、在 asyncio 中阻塞事件循环等原理,对构建高可靠系统至关重要。它广泛应用于请求节流、定时任务、GUI 防冻结和实时数据采集等场景。本文聚 阅读详情

相关推荐

C++ Sleep 函数

C++ Sleep 函数。 Sleep 函数的 S是大写!!!! 今天,我们来讲一下C++中的 Sleep 函数,它的作用是让程序暂停一会。

小天狼星_布莱克 的博客 3万+

理解 Thread.Sleep 函数

转自http://www.cnblogs.com/ILove/archive/2008/04/07/1140419.html我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间。那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题:1、假设现在是 2008-4-7 12:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2008-4-7

greystar的专栏 6018

C++笔记之各种sleep方法总结

C++笔记之sleep总结 —— 2023年4月9日 小问 上海 code review文章目录C++笔记之sleep总结1.std::this\_thread::sleep\_for()附:std::this\_thread::sleep\_for(std::chrono::duration)2.std::this\_thread::sleep\_until()附:std::this\_thread::sleep\_until(std::chrono::time\_point)3.std::chrono:

小勇博客 1万+

C# 理解Thread.Sleep()方法

C# 理解Thread.Sleep()方法 ----转帖 https://www.cnblogs.com/nzbbody/archive/2012/03/06/2381359.html 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间。那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题: 1、假设现在是 2008-4-7 12:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2008-4-7 12:00:01.000 的时候,这个线程会 不会被唤

yjpfinui的博客 6613

手把手教你用STM32CubeMX配置Bootloader:从分区设置到跳转逻辑详解(含完整代码示例)

本文详细介绍了如何使用STM32CubeMX配置STM32 Bootloader,从基础概念到完整实现。涵盖Flash分区设置、跳转逻辑、固件升级协议设计等关键步骤,并提供完整代码示例。适合嵌入式开发者快速掌握Bootloader开发技巧,提升STM32固件升级能力。

weixin_29169505的博客 284

独立站如何采集商品?外贸独立站采集教程

从这里Robert了解到还有国内有很多仿牌卖家、微商,都有类似的情况,他们出海的阻碍主要在于支付、物流、推广。8.插件“抓取任务”列表手动点同步,将商品同步到主商城后台商品管理列表(商品默认同步到下架列表中) 后台商品管理下架列表显示已同步商品。5.店铺信息修改完成后,可以开始采集商品,采集时弹窗中会自动识别当前平台及商品链接,分类和相册名称可以自定义 编辑修改。4. 打开采集目标站商品页面,点开谷歌浏览器扩展程序列表,找到Shopyy采集平台,打开配置页。打开弹窗中的“店铺管理”,添加店铺信息。

Jernnifer_mao的博客 1380

C# Thread.Sleep(0)有什么用?

C# Thread.Sleep(0)有什么用? https://www.zhihu.com/question/404549155/answer/1321501865 C# Thread.Sleep(0)有什么用? C# 异步编程_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​ www.bilibili.com 问题出现在视频的最后,sleep(0)和yield为什么可以发现多线程代码中的BUG,可以解释一下吗,谢谢 关注者 55 被浏览 17,374 登录一下,更多精彩内.

kuangben2000的博客 1177

数字IC后端实战:OCC电路时钟树综合的5个关键技巧(附Synopsys工具配置)

本文深入探讨了数字IC后端设计中OCC电路时钟树综合的实战技巧。针对工具自动平衡导致的绕线拥塞和时序问题,文章提出了分段处理的核心思路,并详细阐述了通过物理隔离、分段长树策略以及Synopsys工具链(如ICC2、PrimeTime)的精准配置来优化function clk与occ clk路径的关键方法,旨在提升时序收敛性和可制造性。

jwt8token的博客 858

公司的代码中看到「Thread.sleep(0)」是Bug吗?

我们可能经常会用到 Thread.Sleep 函数来把使线程挂起一段时间。那么你有没有正确的理解这个函数的用法呢? 思考下面这两个问题: ①、假设现在是 2022-01-01 00:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2022-01-01 00:00:01.000 的时候,这个线程会不会被唤醒? ②、某人的代码中用了一句看似莫明其妙的话:Thread.Sleep(0) 。既然是 Sleep 0 毫秒,那么他跟去掉这句代码相比,有啥区别么?

Darling_qi的博客 356

IEC 104电力规约详细解读(一) - 报文结构、报文分类、ASDU

比如,双方可以按频率发送,比如接收8帧I帧回答一帧S帧,也可以要求接收1帧I帧就应答1帧S帧,当然也可以不要求(S帧内容示例参考例1)。所以U帧格式的控制欲第一个字节就只有6种情况,分别是0x83(TESTER确认)、0x43(TESTER命令)、0x23(STOPDT确认)、0x13(STOPDT命令)、0x0B(START确认)、0x07(START命令)ASDU(应用服务数据单元),协议原文格式最好去101协议去看看,会比较详细。遥信、遥测、遥控、遥调、总召、对时等都需要使用I格式传送。

张二狗的博客 1万+

R语言做一个 GM (1,1)灰色预测模型

累加生成是GM(1,1)模型的另一个重要步骤,它通过构造累加生成序列,把非线性非平稳时间序列转化为线性平稳时间序列。GM(1,1)是一种基于灰色系统理论的预测模型,通常用于中小样本的非线性、非平稳时间序列数据分析。灰色预测模型的核心是灰度处理,将原始时间序列转化为灰色时间序列。这里使用R语言中的diff函数对时间序列进行一次差分,然后对结果取累加和得到灰度序列。以上是GM(1,1)灰色预测模型在R语言中的实现步骤。需要注意的是,GM(1,1)模型适用于中小样本的时间序列预测,对于长期预测效果可能较差。

Mrrunsen的博客 3842

Thread.sleep(0)的隐藏技能:不只是让出CPU这么简单

本文深入探讨了Java中Thread.sleep(0)的隐藏功能,它不仅是简单的让出CPU,更是一种精妙的并发控制工具。文章从线程调度原理出发,分析了其与Thread.yield()的区别,并详细阐述了它在优化自旋锁、缓解线程饥饿、调试竞态条件以及响应中断等实战场景中的应用价值与最佳实践。

oil88的博客 1091

【深度学习新浪潮】手把手教你不花一分的token钱,纯本地部署openclaw

本地轻量开源AI智能体框架Windows 11 + WSL2 + Ollama + OpenClaw 一键部署零代码配置,直接用上本地模型工具调用未来方向:轻量化、插件化、本地生态成熟如果你喜欢本地AI、厌倦了云端限制、想真正拥有一个“听话又能干”的本地助手,OpenClaw 绝对值得现在就上手玩一玩。

专注:太空算力、AI infra、异构调度、大模型成本工程 2785

android sleep 毫秒,如何减少Android中的Thread.sleep()延迟

我在Android应用程序的(非UI)线程中循环生成计时事件,我需要这些事件以精确的时间间隔发生,(这里的精确意味着不会超过/ – 5毫秒).用户可以感知到/ -10毫秒(当然/ – 20毫秒)的任何​​错误.在这个循环的顶部,我做了一些其他计算需要花费不同的时间,但是在循环的底部,我需要在预先计算的时间发生事件.我的非UI线程的一次尝试的高度简化版本(无异常处理)如下:public fi...

weixin_42300398的博客 989

Windows 11 WSL2环境下OpenClaw部署的兼容性问题分析与解决方案研究

本文研究了OpenClaw在Windows 11 WSL2环境下的部署方案。WSL2通过无缝集成Linux与Windows系统,为OpenClaw提供了良好的运行环境,支持GPU加速和跨平台开发。文章详细分析了硬件配置要求(推荐8核CPU/16GB内存/NVMe SSD)、系统选择(Windows 11 Pro+Ubuntu 22.04)以及部署步骤,包括WSL2启用、Linux发行版安装、Python/Node.js/Redis等依赖配置。通过优化.wslconfig文件参数(如内存分

博客 2282

Label Studio 数据标注平台,大模型预训练与微调必备

摘要:LabelStudio是一款开源数据标注工具,支持文本、图像等多种数据类型的标注。本文介绍了其安装方法(通过conda创建环境并pip安装)、基础使用流程(创建项目、导入数据、设置标签、标注导出)以及AI自动标注功能的实现。重点讲解了如何通过MLBackend集成LangChain模型实现自动标注:创建自定义模型类、构建预测链、处理返回结果,最后配置到LabelStudio项目中。该功能可显著提升标注效率,标注人员只需在AI预测结果基础上进行修正。

技术引领业务创新 290

偶发性bug之 thread里的一个不小心return,导致线程循环退出而异常!!!

public void SP_DataReceived1_timeout() { OP_with_com_name rttobj = prod_comm_obj;// get_op_obj_by_com_name(get_comname_by_index(0)); while (isrunning == 1) { System.Threading.Thread.Sleep(20);

net3m33的专栏 430

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Thread.sleep(0)的意义& 多线程详解

我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间。那么你有没有正确的理解这个函数的用法呢?思考下面这两个问题:假设现在是 2008-4-7 12:00:00.000,如果我调用一下 Thread.Sleep(1000) ,在 2008-4-7 12:00:01.000 的时候,这个线程会 不会被唤醒?某人的代码中用了一句看似莫明其妙的话:Thread.Sleep(0) 。既然...

weixin_30449453的博客 66

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

boost::this_thread::sleep_for()死锁

boost::this_thread::sleep_for()会死锁(金庆的专栏)发现睡眠1ms很容易死锁。boost::this_thread::sleep_for(boost::chrono::milliseconds(1)).Boost 1.54.0以下代码很可能重现死锁:#include "stdafx.h"#include #include using namespace std;voi

金庆的专栏 1万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

java foreach循环 thread.sleep不生效_Java代码非常实用的小技巧

来源: https://www.cnblogs.com/Qian123/p/6046096.html 作者:萌小Q前言代码优化 ,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是,吃的小虾米一多之后,鲸鱼就被喂饱了。代码优化也是一样,如果项目着眼于尽快无BUG...

weixin_39637723的博客 2211

Thread 类的基本用法

Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志。public bollean isInterrupted() 判断对象关联的线程的标志位是否设置,调用后不清除标志位。System.out.println("这⾥是线程运⾏的代码");也是我们⽐较熟悉⼀组⽅法,有⼀点要记得,因为线程的调度是不可控的,所以,这个⽅法只能保证。通过共享的标记来进⾏沟通(使用自定义的变量作为标志位)

light_in_hand的博客 674

重学Thread类:理解.NET多线程地基层与并发本质

线程是操作系统调度的最小执行单元,其核心由线程ID、程序计数器(PC)、寄存器集合和私有栈构成;它与进程共享堆内存、文件句柄等资源,但独占栈与线程本地存储(TLS),这一共享/私有模型直接决定并发安全边界。理解Thread生命周期(如Unstarted→Running→WaitSleepJoin→Stopped)、状态转换及同步原语(如ManualResetEvent、Monitor),是诊断死锁、UI冻结、资源泄漏等真实问题的关键基础。尤其在工业控制、WPF图像处理、金融风控等对确定性要求高的场景中,绕过

baochuanying9531的博客 545

Python time.sleep() 原理与高精度等待避坑指南

time.sleep() 是 Python 中最常用却最易被误解的系统级暂停函数,其本质是向操作系统发起让出 CPU 时间片的系统调用,而非简单计时。它基于底层定时器机制(如 nanosleep)实现线程级阻塞,在单线程中表现为同步延迟,在多线程中可释放 GIL 促进调度协作,但在异步环境中直接使用将阻塞整个事件循环。实际精度受操作系统定时器分辨率限制——Windows 默认约15.6ms,Linux 可达微秒级,因此不可用于高精度场景。该函数广泛应用于爬虫限频、CLI 工具节奏控制、自动化脚本等待及多线程

weixin_33827590的博客 471

刚解了个FreeRTOS Timer Queue 满的Bug

车载网关Aurix芯片FreeRTOS timer queue满的bug。

铁匠的七寸宫 1041

Thread 类 -- 2

讲解了线程终止的三种方式:立即终止(break)、不终止或延迟终止。其次说明join()方法用于控制线程执行顺序,包括带超时参数的版本。接着介绍sleep()方法实现线程休眠及其特殊用法(如sleep(0))。最后详细解析了Java线程的6种状态(NEW、TERMINATED、RUNNABLE等)及其转换关系,并提供了线程调试的基本方法,包括状态分析和调用栈检查。这些内容涵盖了线程控制的核心机制,为处理多线程问题提供了实用指导。

z141042的博客 1050

vs2019+PCL1.12.0 代码运行bug汇总

vs2019+PCL1.12.0 代码运行bug汇总

weixin_49805002的博客 1042
上一篇: 比SQL还好用,又一门国产数据库语言诞生了
下一篇: 面试官问如何优化慢SQL?
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值