[英]How to deal with: Call to 'Thread.sleep()' in a loop, probably busy-waiting
伙計們如何處理這樣的代碼和警告?
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
,但它總是在單獨的線程中運行,我需要暫停當前線程。
請幫忙..
這是來自 intellij 的可疑警告,從某種意義上說,您正在做的事情通常是直接需要的。 換句話說,它正在檢測過度使用的模式,但其使用量不能減少到 0。因此,可能正確的解決方案是告訴 intellij 在這里閉嘴。
它正在查看的問題不是Thread.sleep
。 那不是問題。 但是,intellij 的這種模式檢測器需要它來找到這種情況,但這不是它所抱怨的,這可能有點難以理解。
IntelliJ 擔心的是,您會無緣無故地浪費周期不斷地重新檢查log.isEmpty()
。 這段代碼的while
方面有問題,而不是 sleep 。 它更願意看到調用某種logs.poll()
方法的代碼,該方法只會等到它被新日志出現的行為主動喚醒。
如果這一切都在單個 java 進程中運行,那么您確實可以重寫整個系統(包括重寫此處的任何log
,以及對checkLogs()
方法的完全重新想象:而不是出去檢查,無論如何正在制作日志需要喚醒此代碼。
如果不是,您可能需要告訴 intellij 將其關閉:如果沒有完整的系統重新設計,您正在做的事情是不可避免的。
您在這里有一些可悲的異常處理。
不要編寫記錄某些內容並繼續移動的catch
塊。 這是非常糟糕的錯誤處理:系統的變量和字段現在位於未知的 state 中(您剛剛捕獲並記錄了一些內容:當然這意味着您不知道發生了什么條件導致這行執行發生,)。 然而代碼會繼續前進:通常,“捕獲異常並繼續運行”風格的代碼極有可能導致更多異常。 在未知 state 上運行的代碼遲早會崩潰和燒毀。
然后,如果以相同的方式處理崩潰和燒傷(抓住它,記錄它,繼續前進),那么你會得到另一個崩潰和燒傷。 您最終得到的代碼將在遇到問題時將186 個異常打印到日志中,除了第一個異常之外,它們都完全不相關。 太壞了玉玉。
您還使調用代碼完全不可能恢復。 異常的要點是它們需要無休止地向上冒泡:要么異常被實際上知道如何處理問題的代碼捕獲(並且記錄它並沒有處理它),你正在使它成為不可能,或者。 代碼異常應該一直冒泡到入口點處理程序,這是記錄錯誤和中止入口點處理程序的正確位置。
入口點處理程序是通用模塊或應用程序運行器; 開箱即用,最終調用您的psv main()
方法的java.exe
本身的代碼是最明顯的“入口點運行程序”,但還有更多:Web 框架最終將調用您的一些代碼處理 web 請求:您的代碼類似於psv main()
:它是入口點,調用它的 web 框架中的代碼是入口點運行器。
入口點運行程序有充分的理由來catch (Throwable t)
,並主要將其捕獲塊用於記錄它,盡管它們通常應該記錄的不僅僅是異常(例如,web 處理程序應該記錄請求詳細信息,例如發送了哪個 HTTP 參數以及它是哪個路徑請求,可能是標頭等)。 但是,任何其他代碼都不應該這樣做。
如果您不知道該做什么並且不想考慮該異常可能意味着什么,那么正確的“無論如何,只需編譯 javac”代碼策略就是將異常類型添加到throws
行。 如果這不可行,那么 catch 塊中的正確代碼是:
} catch (ExceptionIDoNotWantToThinkAboutRightNow e) {
throw new RuntimeException("Uncaught", e);
}
這將確保代碼不僅會愉快地繼續前進,在未知的 state 上運行,還將確保您在日志中獲得完整的詳細信息,並確保調用代碼可以捕獲並處理它,並確保任何自定義日志記錄信息,例如由於 HTTP 請求詳細信息有機會進入日志。 三贏三贏。
當在 java 進程中運行的某些代碼調用yourThread.interrupt()
時,這就是可能發生InterruptedException
的方式,並且不可能以任何其他方式發生。 如果用戶按 CTRL+C,或者進入任務管理器並單擊“結束進程”,或者如果您的 android 手機決定是時候讓您的應用退出,因為 memory 需要其他東西 -這些情況都不可能導致中斷異常。 您的線程只是被 java 中途殺死(如果您想對關機采取行動,請使用Runtime.getRuntime().addShutdownHook
)。 唯一的方法是讓一些代碼調用.interrupt()
,而核心庫中的任何內容都不會這樣做。 因此,InterruptedException 意味着您認為“此線程上的 call.interrupt()”意味着什么。 它是由你決定。
最常見的定義實際上是“我請你停止”:只是很好地關閉線程。 通常,如果您想退出整個 VM,嘗試很好地關閉線程是不好的(只需調用System.shutdown
- 您已經需要處理用戶按 CTRL+C,為什么要以不同的方式編寫兩次關閉代碼?) - 但是有時你只想讓一個線程停止。 因此,通常放入catch (InterruptedException e)
塊的最佳代碼就是return;
沒有別的了。 不要記錄任何東西:“中斷”是故意的:你寫的。 這很可能不在您的代碼庫中,並且 InterruptedException 沒有實際意義:它永遠不會發生。
在您的特定代碼中,如果您的代碼決定停止記錄器線程會發生什么,記錄器線程會將某些內容記錄到錯誤日志中,然后將縮短其 2 秒的等待時間以立即檢查日志,然后繼續運行。 這聽起來完全沒用。
但是,它意味着任何你想要的。 如果您希望用戶能夠點擊“立即強制檢查日志”按鈕,那么您可以定義中斷日志記錄線程只是縮短 2 秒(但隨后只有一個帶有注釋的空 catch 塊,解釋該這就是你設計的方式,顯然不要記錄它)。 如果您還想要一個按鈕來“停止日志記錄線程”,請使用一個 AtomicBoolean 來跟蹤“正在運行”state:當點擊“停止日志刷新”按鈕時,將 AB 設置為“假”,然后中斷線程:然后您粘貼的代碼需要檢查AB並return;
如果它是false
則關閉線程。
fun sleep(timeMillis: Long) {
val currentTimeMillis = System.currentTimeMillis()
while (true) {
if (System.currentTimeMillis() - currentTimeMillis >= timeMillis) {
break
}
}
}
並在你的方法中使用它(這是 koltin 的代碼,你應該轉換為 java)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.