为什么不推荐在 while 循环中使用 sleep()

前言

  • 最近逛 CSDN 看到一篇文章,文章大意是说为什么在循环中不推荐使用 sleep 操作,原因在于线程挂起和唤醒会有很大的性能消耗,并推荐使用 Timer 及 ScheduledExecutorService 方案进行优化,下面我简单复现一下具体代码,大家思考一下,原文的原因以及解决方案是否合理:
java 复制代码
public class Demo {

    private static final boolean FLAG = true;

    public static void main(String[] args) {
        while (FLAG) {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        
        // do something
    }
}
  • 上面的代码你可能会得到下面的警告:
java 复制代码
Call to 'Thread.sleep()' in a loop, probably busy-waiting
// 循环中调用 sleep 可能会导致忙等待 
// 如 FLAG 变量状态未改变 那么线程可能一直循环,并不断进行线程挂起和唤醒

原因是否正确

  • 主要原因和原文博主所说有很大的关系但不完全正确:
  • 我们都知道 Java 线程实际对应着操作系统中的一个线程,对线程的挂起和唤醒是一个很耗性能的操作,因此我们需要避免对线程进行挂起和唤醒;
  • 但还一个重要的原因是忙等待,如上文所示 FLAG 变量的状态可能永远不会被改变,那么线程将会不断进行挂起和唤醒,进入忙等待状态,造成资源的浪费。

方案是否合理

  • 记住一点,讨论方案永远不能脱离场景,没有一种方案可以适应所有的场景,我们永远只是在探讨适合当前场景的方案。因此,原文博主只是提供了一些场景下的方案,下面我们结合一些具体的场景来探讨一些可行的方案:

定时轮询场景

  • 定时轮询的场景我们可以采用博主提供的思路,比如 Timer 及 ScheduledExecutorService 或者其它一些定时机制方案。

    比如微服务体系中,客户端上报实例状态,或者服务端检测客户端状态都会使用定时轮询的机制。

事件机制

  • 上文的场景,我更推荐事件机制进行解耦,当变量被改变时,发送变量修改事件进行处理,如常见的 Spring Event 或者其它事件推送框架。

    比如一些用户登录场景,当用户登录状态改变时,发送登录事件进行后续处理,比如登录通知等等

等待和唤醒

  • 等待和唤醒机制一般适用于等待时间较长的场景,因为等待和唤醒是一个性能消耗比较大的操作;在等待时间不是很长的场景可以使用轮询机制,避免线程频繁的挂起和唤醒。

    在 Java AQS 等待获取锁和线程池任务为空等待新任务时,会使用等待和唤醒操作
    轮询机制 和 等待和唤醒 一般会结合使用,避免线程频繁的挂起和唤醒。

个人简介

👋 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

🚀 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

🧠 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

💡 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

🌐 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

📖 保持关注我的博客,让我们共同追求技术卓越。

相关推荐
一只特立独行的猪6111 小时前
Java面试——集合篇
java·开发语言·面试
吃面不喝汤661 小时前
Flask + Swagger 完整指南:从安装到配置和注释
后端·python·flask
讓丄帝愛伱2 小时前
spring boot启动报错:so that it conforms to the canonical names requirements
java·spring boot·后端
weixin_586062022 小时前
Spring Boot 入门指南
java·spring boot·后端
Dola_Pan5 小时前
Linux文件IO(二)-文件操作使用详解
java·linux·服务器
wang_book5 小时前
Gitlab学习(007 gitlab项目操作)
java·运维·git·学习·spring·gitlab
蜗牛^^O^6 小时前
Docker和K8S
java·docker·kubernetes
从心归零7 小时前
sshj使用代理连接服务器
java·服务器·sshj
王中阳Go7 小时前
字节跳动的微服务独家面经
微服务·面试·golang
IT毕设梦工厂8 小时前
计算机毕业设计选题推荐-在线拍卖系统-Java/Python项目实战
java·spring boot·python·django·毕业设计·源码·课程设计