喪心病狂,竟有Thread.sleep(0)這種寫法?
theme: cyanosis
如果本文對你有幫助的話,救救孩子吧,可以投很多票,投票通道 ,萬分感謝呀~~
前言
最近在網上看到了一段程式碼,讓我感到很迷茫。他在程式碼中使用了Thread.sleep(0)
,讓執行緒休眠時間為0秒,具體程式碼如下。
``` int i = 0; while (i<10000000) { // business logic
//prevent long time gc
if (i % 3000 == 0) {
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} ```
sleep
了0秒,不就是不睡覺嗎?我的第一反應是這段程式碼沒什麼用,但是看到他的註釋又引起了我的興趣。經過一番研究,看似無用的一段程式碼,其實大有文章。
探索分析
為了找到原因,首先去看下sleep
方法的javadoc
,如下:
Causes the currently executing thread to sleep (temporarily ceaseexecution) for the specified number of milliseconds, subject tothe precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.
顯然沒有得到正確的答案,最後在詢問作者說是使用Thread.sleep(0)
可以暫時釋放CPU時間線。
時間片迴圈排程演算法
在作業系統中,CPU有很多競爭策略。Unix系統採用時間片迴圈排程演算法。在該演算法中,所有程序都被分組到一個佇列中。作業系統按順序為每個程序分配一定的時間,即允許程序執行的時間。如果在時間片結束時程序仍在執行,則CPU將被剝奪並分配給另一個程序,如果程序在時間片內阻塞或結束,則CPU立即切換。排程程式所要做的就是維護一個就緒程序表。當程序用完時間片時,它將被移到佇列的末尾。
上面的程式碼中存在死迴圈。作者希望一直用一個執行緒來處理業務邏輯。如果Thread.sleep(0)
不使用主動放棄CPU時間片,執行緒資源會一直被佔用。眾所周知,GC 執行緒具有低優先順序,因此Thread.sleep(0)
用於幫助 GC 執行緒嘗試競爭 CPU 時間片。但是為什麼作者說可以防止long time GC
呢?這就講到JVM的垃圾回收原理了。
GC的安全點
以HotSpot
虛擬機器為例,JVM並不會在程式碼指令流的任何位置暫停以啟動垃圾回收,而是強制執行必須到達安全點才暫停。換句話說,在到達安全點之前,JVM 不會為 GC STOP THE WORLD
。
JVM 會在一些迴圈跳轉和方法呼叫上設定安全點。不過,為了避免安全點過多帶來的沉重負擔,HotSpot虛擬機器還有一個針對迴圈的優化措施。如果迴圈次數少,執行時間不宜過長。因此,預設情況下不會將使用 int 或更小資料型別作為索引值的迴圈放置在安全點中。這種迴圈稱為可數迴圈。相應地,使用long或更大範圍的資料型別作為索引值的迴圈稱為未計數迴圈,將被放置在安全點。
但是,我們這裡正好有一個可數迴圈,所以我們的程式碼不會放在安全點。因此,GC執行緒必須等到執行緒執行完畢,才能執行到最近的安全點。但如果使用Thread.sleep(0)
,則可以在程式碼中放置一個安全點。我們可以看下HotSpot
的safepoint.cpp
原始碼中的註釋,做除了說明。
// Begin the process of bringing the system to a safepoint.
// Java threads can be in several different states and are
// stopped by different mechanisms:
//
// 1. Running interpreted
// The interpeter dispatch table is changed to force it to
// check for a safepoint condition between bytecodes.
// 2. Running in native code
// When returning from the native code, a Java thread must check
// the safepoint _state to see if we must block. If the
// VM thread sees a Java thread in native, it does
// not wait for this thread to block. The order of the memory
// writes and reads of both the safepoint state and the Java
// threads state is critical. In order to guarantee that the
// memory writes are serialized with respect to each other,
// the VM thread issues a memory barrier instruction
// (on MP systems). In order to avoid the overhead of issuing
// a memory barrier for each Java thread making native calls, each Java
// thread performs a write to a single memory page after changing
// the thread state. The VM thread performs a sequence of
// mprotect OS calls which forces all previous writes from all
// Java threads to be serialized. This is done in the
// os::serialize_thread_states() call. This has proven to be
// much more efficient than executing a membar instruction
// on every call to native code.
// 3. Running compiled Code
// Compiled code reads a global (Safepoint Polling) page that
// is set to fault if we are trying to get to a safepoint.
// 4. Blocked
// A thread which is blocked will not be allowed to return from the
// block condition until the safepoint operation is complete.
// 5. In VM or Transitioning between states
// If a Java thread is currently running in the VM or transitioning
// between states, the safepointing code will wait for the thread to
// block itself when it attempts transitions to a new state.
可以看上面的第2點 Running in native code
,而Thread.sleep(long millis)
是一種native
方法。
總結
Thread.sleep(0)
不是什麼無用的程式碼。sleep
方法可用於在 java 程式碼中放置一個安全點。可以提前在長迴圈中觸發GC,避免GC執行緒長時間等待,從而避免達到拉長GC時間的目的。
如果本文對你有幫助的話,救救孩子吧,可以投很多票,投票通道 ,萬分感謝呀~~
- Java7到Java17, Switch語句進化史
- 樂觀鎖思想在JAVA中的實現——CAS
- 一步步帶你設計MySQL索引資料結構
- 我總結了寫出高質量程式碼的12條建議
- 工作這麼多年,我總結的資料傳輸物件 (DTO) 的最佳實踐
- Spring專案中用了這種解耦模式,經理對我刮目相看
- 大資料HDFS憑啥能存下百億資料?
- 5個介面效能提升的通用技巧
- 你的哪些SQL慢?看看MySQL慢查詢日誌吧
- 90%的Java開發人員都會犯的5個錯誤
- 喪心病狂,竟有Thread.sleep(0)這種寫法?
- 為什麼更推薦使用組合而非繼承關係?
- 一個30歲程式設計師的覺醒和進擊
- 推薦8個提高工作效率的IntelliJ外掛
- 公司的這種打包啟動方式,我簡直驚呆了
- 告別醜陋判空,一個Optional類搞定
- 你不知道的Map家族中的那些冷門容器
- SpringBoot 2.x整合Log4j2日誌
- SpringBoot應用自定義logback日誌
- 你確定懂了Java中的序列化機制嗎