当前位置: 首页 > 知识库问答 >
问题:

如何处理:在循环中调用“thread.sleep()”,可能是busy-waiting

尹承业
2023-03-14

伙计们如何处理这样的代码和警告?

private void listenOnLogForResult() {
    String logs = "";
    int timeCounter = 1;
    while (logs.isEmpty()) {
        try {
            timeCounter++;
            Thread.sleep(2000); // Wait 2 seconds
        } catch (InterruptedException e) {
            log.error(e.getLocalizedMessage(), e);
        }
        if (timeCounter < 30) {
            logs = checkLogs()
        } else {
            logs = "Time out";
        }
    }
}

我已经尝试过许多executorservice,但它总是在单独的线程中运行,我需要暂停当前的线程。

请帮帮忙..

共有1个答案

邓正谊
2023-03-14

这是一个来自intellij的警告,它是可疑的,因为你所做的往往是直接需要的。换句话说,它正在检测一个过度使用的模式,但其使用率不能减少到0。所以,正确的解决方案可能是告诉intellij在这里闭嘴。

它所关注的问题不是thread.sleep。这不是问题所在。然而,Intellij的这种模式的检测器需要它来找到这个案例,但它并不是它所抱怨的,这可能有点难以缠住你的头。

IntelliJ担心的是,您无缘无故地不断地重新检查log.isempty()浪费了周期。这段代码的while方面有问题,而不是睡眠。它更希望看到调用某种logs.poll()方法的代码,该方法将一直等到新日志出现时才被主动唤醒。

如果所有这些都在一个Java进程中运行,那么您确实可以重写整个系统(其中包括重写这里的log以及对checklogs()方法的完全重新想象:不是出去检查,而是任何正在制作日志的东西都需要唤醒这段代码。

如果不是,那么您可能需要告诉intellij关闭它:如果没有完整的系统重新设计,您正在做的事情是不可避免的。

这里有一些糟糕的异常处理。

不要编写catch块来记录某些内容并保持移动。这是非常糟糕的错误处理:系统的变量和字段现在处于未知状态(您只是捕获并记录了一些内容:这当然意味着您不知道发生了什么情况导致执行这一行!),但是代码仍然会继续运行。“捕获异常并继续执行”风格的代码极有可能导致更多的异常:通常,在未知状态下操作的代码会更快而不是更晚地崩溃和烧毁。

然后,如果以相同的方式处理该崩溃和燃烧(捕获它,记录它,继续运行),那么您将得到另一个崩溃和燃烧。您最终得到的代码会在遇到问题时将186个异常打印到日志中,除了第一个之外,它们都是完全不相关的。那是坏玉玉。

您还使调用代码完全无法恢复。异常的关键在于它们需要无休止地向上冒出:或者异常被实际知道如何处理问题的代码捕获(记录它并不是在处理它!),这是不可能的,或者,代码异常应该一直冒出到入口点处理程序,这是记录错误并中止入口点处理程序的正确位置。

入口点处理程序是通用模块或应用程序运行程序;开箱即用,最终调用psv main()方法的java.exe本身的代码是最明显的“入口点运行器”,但还有更多的:Web框架最终将调用您的一些应该处理Web请求的代码:您的代码类似于psv main():它是入口点,Web框架中调用它的代码是入口点运行器。

入口点运行程序有很好的理由来catch(Throwable t),并将其catch块主要用于记录它,尽管它们通常应该记录的不仅仅是异常(例如,web处理程序应该记录请求的详细信息,例如发送了哪些HTTP参数,它是哪个路径请求,可能是头,等等)。但是,任何其他代码都不应该这样做。

如果您不知道该做什么,也不想考虑异常可能意味着什么,那么正确的“whatever,just compile eight javac”代码策略是将异常类型添加到throws行中。如果不可行,则catch块中的正确代码为:

} catch (ExceptionIDoNotWantToThinkAboutRightNow e) {
    throw new RuntimeException("Uncaught", e);
}

这将确保代码不会愉快地继续在未知状态下操作,并确保您在日志中获得完整的详细信息,确保调用代码能够捕获并处理它,并确保任何自定义日志信息(如HTTP请求详细信息)都有机会将其写入日志。共赢共赢。

当运行在该Java进程中的某些代码调用YourThread.Interrupt()时,这就是InterruptedException的发生方式,而它不可能以任何其他方式发生。如果用户点击Ctrl+C,或者进入任务管理器并点击“结束进程”,或者如果你的android手机决定是时候让应用程序退出了,因为需要内存来做其他事情--这些情况都不可能导致中断。您的线程只是在中途被Java杀死(如果您想对关闭采取行动,请使用runtime.getruntime().addShutDownHook)。唯一的方法是某些代码调用.interrupt(),而核心库中没有任何东西可以做到这一点。因此,InterruptedException意味着您认为'call.interrupt()on this thread'意味着什么。由你决定。

最常见的定义实际上是“I ask you to stop”:只需很好地关闭线程。通常,如果您想退出整个VM,那么尝试良好地关闭线程是不好的(只需调用system.shutdown-您已经需要处理用户按Ctrl+C键,为什么要用不同的方式编写两次关闭代码?)--但有时你只想让一个线程停下来。因此,通常放入catch(InterruptedException e)块的最佳代码只是return;而不是其他。不要记录任何内容:“中断”是有意的:是你写的。最有可能的是,这在您的代码库中是没有的,InterruptedException是没有意义的:它永远不会发生。

在您的特定代码中,如果您的代码决定停止记录器线程,则会发生这样的情况:记录器线程将某些内容记录到错误日志中,然后将其2秒的等待时间缩短以立即检查日志,然后继续执行。听起来完全没用。

但是,这意味着你想要的一切。如果你想让用户点击一个“立即强制检查日志”按钮,那么你可以定义中断日志记录线程仅仅是2秒的快捷方式(但之后只需要一个空的catch块,并附上一个注释,解释这是你设计的,显然不记录它)。如果您还想要一个“停止日志记录线程”的按钮,请使用一个AtomicBoolean来跟踪“运行”状态:当单击“停止日志刷新”按钮时,将AB设置为“false”,然后中断线程:那么您粘贴的代码需要检查AB并返回;如果是false则关闭线程。

 类似资料:
  • 问题内容: 我试图用NodeJS编写代码,从外部API抓取数据,然后使用Mongoose在MongoDB中填充它们。在这之间,我将检查该特定对象是否已经存在于Mongo中。下面是我的代码。 我的问题是,由于NodeJS回调是并行的,因此不会按顺序调用它。我的最终结果将是这样的: 呼叫报告API console.log(长度)= 100 ^^^^^^^^^^^^^^^^^^^^^^^^^ conso

  • 从我的main开始,我将启动两个线程,称为producer和consumer。两者都包含循环。生产者循环是UDP服务器,因此不需要Hibernate。我的问题出在消费者方面。使用者循环将对象从链接队列中移除,并将其传递给一个函数进行进一步处理。根据研究,在循环中使用线程Hibernate不是一个好的实践,因为有时O/S在设定时间结束时不会释放。如果我删除线程Hibernate,当应用程序是理想的,

  • 问题内容: 在NetBeans中,有一个新提示: Thread.sleep在循环中调用。 问题1: 循环睡眠的时间/时间是什么时候? 问题2: 如果有问题,我该怎么办? 更新:问题3: 这是一些代码。在这种情况下,请告诉我是否应该在循环中使用其他方法代替Thread.Sleep。简而言之,它由侦听客户端TCP连接的服务器使用。如果达到与客户端的最大会话数,则在此处使用睡眠。在这种情况下,我希望应用

  • 下面是我的父组件,它包含一个循环的多个输入。如何选择一个来聚焦?在这种情况下,我必须创建动态吗?

  • 问题内容: 可以说我必须在for循环内使用if语句,并且for循环在特定条件下触发,而if语句仅在for循环达到特定阶段时才触发。 例如,条件是一个计数器,该计数器在发生某些事情(例如,球从屏幕上掉下来)时进行计数。每次球越过屏幕时,都会一圈绘制一个圆圈。当第一行中的圆圈到达屏幕的末端时,圆圈开始出现在第一行下方的第二行中。但是第二行对我不起作用,我已经用if语句实现了。 if语句仅在第一行的球越

  • 这里是一个以圆圈为单位的交叉网格,当前为5x5。我试图得到一行5,下面是一行4,然后是3,然后是2等等。我试着改变for循环和值,但什么都不起作用。我需要使用行和列吗? 谢谢!