当前位置: 首页 > news >正文

挂起、阻塞、锁和cpu占用

Thread.sleep()Object.wait()

在 Java 多线程编程中,Thread.sleep()Object.wait()都能让线程暂停执行,但它们的目的机制和使用场景有本质区别。

核心区别总结

  • 所属类不同

    • sleep()是 ‌Thread类的静态方法‌,作用于当前线程。
    • wait()是 ‌Object类的实例方法‌,作用于某个对象的监视器(锁)。
  • 是否释放锁‌(最核心区别)

    • sleep()不会释放任何锁‌,线程仍持有同步块或方法中的锁。
    • wait()会立即释放当前对象的锁‌,允许其他线程获取该锁并执行同步代码。
  • 调用前提

    • sleep()可在‌任意位置调用‌,无需同步上下文。
    • wait()必须在synchronized代码块或方法中调用‌,否则抛出IllegalMonitorStateException
  • 唤醒方式

    • sleep()在指定时间结束后‌自动恢复‌;也可被interrupt()中断。
    • wait()需要其他线程调用同一对象的notify()notifyAll()才能唤醒;也可带超时参数(如wait(1000))或被中断唤醒。
  • 线程状态

    • sleep()使线程进入 ‌TIMED_WAITING‌ 状态,是一种挂起函数‌,它使线程暂时挂起(进入TIMED_WAITING状态)。
    • wait()(无参)使线程进入 ‌WAITING‌ 状态;带超时的wait(long)进入 ‌TIMED_WAITING‌。
  • 典型使用场景

    • sleep():用于‌延迟执行‌、控制轮询间隔、模拟耗时操作等‌单线程节奏控制,适用于需要‌定时暂停‌的场景(如限速、模拟延迟等)‌。
    • wait():用于‌线程间协作与通信‌,如生产者-消费者模型,等待某条件满足后再继续。

使用建议

  • 若只需‌让线程暂停一段时间‌,用Thread.sleep()
  • 若需‌等待某个条件成立并与其他线程协作‌,用wait()+notify()/notifyAll(),并配合while循环检查条件以避免虚假唤醒。
  • 切勿在非同步上下文中调用wait()‌,否则运行时异常。
  • 避免用线程对象调用sleep()‌(如t.sleep()),应使用Thread.sleep(),因它是静态方法,语义上属于“当前线程休眠”。

Thread.sleep()方法会阻塞线程但不会占用 CPU 资源

核心结论

  • 不占用 CPU‌:调用Thread.sleep()后,当前线程会进入‌阻塞(BLOCKED/TIMED_WAITING)状态‌,JVM 会将其从调度队列中移除,‌不再分配 CPU 时间片‌,因此‌不会消耗 CPU 资源‌‌。
  • 释放 CPU 控制权‌:线程主动让出 CPU,操作系统可将 CPU 分配给其他就绪线程,有助于降低整体 CPU 负载‌。

补充说明

  • 仍持有锁‌:虽然释放了 CPU,但 ‌Thread.sleep()不会释放已获取的同步锁(如synchronizedReentrantLock‌,这与Object.wait()有本质区别‌。
  • 线程池中的影响‌:在使用线程池时,调用sleep()的线程‌仍占用线程池中的一个线程槽位‌,无法执行其他任务,可能降低线程池吞吐量‌。
  • 上下文切换开销‌:线程从阻塞恢复为就绪状态时,操作系统需进行上下文切换,此过程有轻微开销,但‌不属于Thread.sleep()直接导致的 CPU 占用‌‌。

常见误区

  • ❌ “sleep()占用 CPU” —— 实际是‌未使用 sleep 的忙等待(busy-wait)才导致高 CPU 占用‌‌。
  • ✅ 正确做法:在循环中加入Thread.sleep()可显著降低 CPU 使用率,例如从 100% 降至 3% 左右‌。

综上,‌Thread.sleep()是一种高效、低开销的线程暂停机制,适用于需要延时或降低 CPU 负载的场景‌。

Kotlin 协程的挂起不会阻塞线程

这是协程区别于传统线程阻塞机制的核心优势之一。

关键要点

  • 挂起(suspend)‌ 是协程内部的状态暂停,仅暂停当前协程的执行,‌不会阻塞底层线程‌,线程可继续执行其他任务。
  • 阻塞(blocking)‌ 是指线程被占用,无法执行其他工作,直到操作完成(如Thread.sleep()或同步 I/O)。
  • 协程通过 ‌Continuation 机制‌ 和 ‌状态机‌ 实现挂起与恢复,在挂起点保存上下文后释放线程,待异步操作完成后再调度恢复执行。

实际影响

  • 在 Android 开发中,使用suspend函数(如withContext(Dispatchers.IO))执行网络请求或数据库操作时,‌主线程不会被阻塞‌,UI 保持响应。
  • 若在主线程直接调用阻塞式 API(如同步 HTTP 请求),‌即使在外层启动了协程,仍会导致 ANR‌,因此必须配合withContext(Dispatchers.IO)等调度器使用。

总结

  • ✅ ‌挂起 = 非阻塞‌:协程挂起时,线程被让出可处理其他协程。
  • ❌ ‌阻塞 = 线程占用‌:应避免在主线程或协程中使用阻塞式调用(如Thread.sleep()、同步 I/O)。
  • 📌 最佳实践:所有可能耗时的操作(网络、文件、数据库)应在suspend函数内使用withContext(Dispatchers.IO)包装,确保主线程安全。
http://www.jsqmd.com/news/620609/

相关文章:

  • MacCMSPro视频影视系统源码:构建专业视频平台的理想选择
  • 我是如何压缩 CLAUDE.md / AGENTS.md 的:尽可能节约 AI 的 Token 消耗
  • 武昌区文化墙设计制作一体
  • 基于PLC的私人车库自动门毕业设计:软件为博图1200,采用梯形图、组态动画、接线图及IO分配表
  • 短纤针刺非织造土工布性能指标及标准;短纤土工布
  • align-items 和 align-self,
  • 实战解析:基于Selenium与多线程的东方财富股吧数据采集方案
  • ComfyUI Manager完整教程:高效管理你的AI绘画插件生态
  • OPUS编解码器在audio DSP上的移植和应用贫
  • 打字不如说话,说话不如截图——AI 代码助手的多模态输入实践仝
  • 别再吹牛了,% Vibe Coding 存在无法自洽的逻辑漏洞!衙
  • Cursor+DeepSeek省钱攻略:每月省下20刀,手把手教你配置国产大模型
  • AspNet MVC4 教学:AspNet MVC4 页面动态生成演示
  • LLM 最大支持的提示词注意事项: Python字符串最大长度完全解析
  • 告别默认样式:CSS 自定义滚动条从入门到实战
  • Jenkins 学习总结暗
  • 别再用扁网线了!实测小米AX3600刷OpenWRT后断流的元凶排查与硬件避坑指南
  • SEATA分布式事务——AT模式凭
  • 逆向实战:Frida Hook JNI动态注册函数的三种核心路径剖析
  • 如何修改 Git 账号,以便拉取和上传别人权限下的项目
  • Spring IOC 源码学习 声明式事务的入口点缸
  • 避坑指南:TwinCAT3 ADS通讯中WSTRING乱码的3种解决方案
  • Redis持久化:从AOF到RDB,如何实现数据不丢失?谑
  • OpenClaw小技巧:Qwen2.5-VL-7B模型输出格式的精准控制
  • jd-happy:京东商品自动监控下单终极指南,告别抢购烦恼
  • 2026届最火的十大降重复率工具推荐榜单
  • 分层强化学习(HRL)在游戏AI中的应用:以《星际争霸》为例
  • Verilog模块批量例化实战:for循环与数组方法对比(附Verdi调试技巧)
  • Guohua Diffusion 10分钟快速入门:无需代码的WebUI界面详解
  • 低成本监控方案:OpenClaw+千问3.5-35B-A3B-FP8实现服务器日志智能分析