繁忙等待的警告
这是来自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框架中的代码则是入口点运行器。
入口点运行器有充分的理由去捕获(Throwable t),并在catch块中主要记录日志,尽管它们通常应该记录更多的内容,而不仅仅是异常(例如,Web处理程序应该记录请求的详细信息,比如发送了哪些HTTP参数,请求的路径是什么,可能还有头部等)。然而,任何其他代码都不应该这样做。
如果你不知道该怎么做,也不想考虑异常可能意味着什么,正确的“随便了,只要编译通过javac”代码策略是将异常类型添加到你的throws行中。如果这不可行,catch块中的正确代码是:
} catch (ExceptionIDoNotWantToThinkAboutRightNow e) {
throw new RuntimeException("Uncaught", e);
}
这将确保代码不会只是愉快地继续运行在未知状态上,并确保您在日志中获得完整的详细信息,并确保调用代码可以捕获并处理它(如果可能的话),并确保任何自定义的日志信息(如HTTP请求详细信息)有机会记录到日志中。四赢。
特别是这种情况:InterruptedEx是什么意思?
当在Java进程中运行的某些代码调用yourThread.interrupt()时,就会发生InterruptedException,而且
没有其他方式可以发生InterruptedException。如果用户按下CTRL+C,或者进入任务管理器并点击“结束进程”,或者如果您的Android手机决定是时候让您的应用退出,因为内存需要用于其他用途-
没有这些情况可能导致InterruptedException。您的线程只会被Java在中间步骤中终止(如果您想在关闭时采取措施,请使用Runtime.getRuntime().addShutdownHook)。唯一的方法是某些代码调用.interrupt(),核心库中没有任何内容会这样做。因此,InterruptedException意味着您认为“在此线程上调用.interrupt()”。这取决于您。
最常见的定义是“我请求你停止”:友好地关闭线程。通常情况下,如果你想退出整个虚拟机(只需调用
System.shutdown
- 你已经需要处理用户按下CTRL+C的情况,为什么要以不同的方式编写两次关闭代码?),友好地关闭线程是不好的 - 但有时你只想让一个线程停止。因此,通常在
catch (InterruptedException e)
块中放入的最佳代码只是
return;
,什么都不做。不要记录任何东西:中断是有意的:是你自己写的。很可能在你的代码库中根本找不到这个InterruptedException,所以它永远不会发生。
在你的具体代码中,如果你的代码决定停止记录器线程,那么记录器线程将向错误日志中记录一些内容,然后将其2秒的等待时间缩短为立即检查日志,然后继续执行。这听起来完全没有用处。
但是,它的意思取决于你想要的。如果你想要一个能让用户立即点击“强制检查日志”按钮的功能,那么你可以定义中断日志线程只是为了节省2秒的时间(但是请确保有一个空的catch块,并在注释中解释这是你的设计方式,显然不要记录它)。如果你还想要一个“停止日志线程”的按钮,可以使用AtomicBoolean来跟踪“运行”状态:当点击“停止日志刷新”按钮时,将AB设置为“false”,然后中断线程:然后你粘贴的代码需要检查AB并且
return;
以关闭线程,如果AB为
false
。