8

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

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";
        }
    }
}

我需要将当前线程暂停 2 秒以等待文件被填充,但我的 Intelij Rise 出现问题。 在此处输入图像描述 而且我从声纳收到错误:SonarLint:要么重新中断此方法,要么重新抛出“InterruptedException”。

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

请帮忙..

4

1 回答 1

9

等待忙碌的警告

这是来自 intellij 的可疑警告,从某种意义上说,您正在做的事情通常是直接需要的。换句话说,它正在检测过度使用的模式,但其使用量不能减少到 0。因此,可能正确的解决方案是告诉 intellij 在这里闭嘴。

它正在研究的问题不是那个Thread.sleep。那不是问题。但是,intellij 的这种模式检测器需要它来找到这种情况,但这不是它所抱怨的,这可能有点难以理解。

IntelliJ 担心的是,您正在浪费周期不断地log.isEmpty()无缘无故地重新检查。这段代码的方面有问题while,而不是 sleep。它更愿意看到您调用某种logs.poll()方法的代码,该方法只会等到它被新日志出现的行为主动唤醒。

如果这一切都在单个 java 进程中运行,那么您确实可以重写整个系统(包括重写log此处的任何内容,以及对该方法的完全重新想象checkLogs():与其出去检查,不如日志需要的任何内容改为唤醒此代码。

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

重新中断警告

您在这里有一些可悲的异常处理。

您的一般异常处理

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

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

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

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

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

如果您不知道该做什么并且不想考虑该异常可能意味着什么,那么正确的“无论如何,只需编译 javac”代码策略就是将异常类型添加到您的throws行中。如果这不可行,那么 catch 块中的正确代码是:

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

这将确保代码不仅会愉快地继续前进,在未知状态下运行,还将确保您在日志中获得完整的详细信息,并确保调用代码可以捕获并处理它,并确保任何自定义日志信息如因为 HTTP 请求详细信息有机会进入日志。三赢三赢。

特别是这种情况:InterruptedEx 是什么意思?

当在该 java 进程中运行的某些代码调用yourThread.interrupt()时,这是怎么InterruptedException发生的,并且不可能以任何其他方式发生。如果用户按下 CTRL+C,或者进入任务管理器并点击“结束进程”,或者如果您的 android 手机决定是时候让您的应用退出,因为其他东西需要内存 -这些情况都不可能导致中断异常。你的线程只是被java中途杀死(如果你想对关闭采取行动,请使用Runtime.getRuntime().addShutdownHook)。唯一的方法是调用一些代码.interrupt(),而核心库中的任何内容都不会这样做。因此,InterruptedException 意味着您认为“在此线程上调用 .interrupt()”意味着什么。它是由你决定。

最常见的定义实际上是“我请你停止”:只是很好地关闭线程。通常,如果您想退出整个 VM,尝试很好地关闭线程是不好的(只需调用System.shutdown- 您已经需要处理用户按 CTRL + C,为什么要以不同的方式编写两次关闭代码?) - 但有时您只是想要一个线程停止。所以,通常最好的代码放在一个catch (InterruptedException e)块中, return;此而已。不要记录任何东西:“中断”是故意的:你写的。这很可能不在您的代码库中,并且 InterruptedException 没有实际意义:它永远不会发生。

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

但是,它意味着任何你想要的。如果您希望用户能够点击“立即强制检查日志”按钮,那么您可以定义中断日志记录线程只是缩短 2 秒(但随后只有一个带有注释的空 catch 块,解释该这就是你设计的方式,显然不要记录它)。如果您还想要一个按钮来“停止日志记录线程”,请使用 AtomicBoolean 来跟踪“运行”状态:当“停止日志刷新”按钮被点击时,将 AB 设置为“假”,然后中断线程:然后您粘贴的代码需要检查 AB,return;如果是则关闭线程false

于 2021-03-23T14:15:19.793 回答