在 KEmulator 重構 EventQueue 時發現:跑 MI3、Gangstar 等遊戲,CPU 瞬間飆至 100%。排查定位到遊戲主迴路 while(true) { ... Thread.yield(); }。本文通過實測對比 yield() 與 sleep(1),揭示底層差異並給出最佳實踐。
// 典型問題遊戲迴路
public void run() {
while (true) {
// 遊戲邏輯、渲染
Thread.yield(); // 試圖讓出 CPU
}
}
| 特性 | Thread.yield() | Thread.sleep(1) |
|---|---|---|
| 語義 | 提示調度器:我願意讓出 CPU,若有其他就緒執行緒請調度它們 | 強制當前執行緒進入 TIMED_WAITING 狀態,至少 1ms 不參與調度 |
| 無其他就緒執行緒時 | **繼續執行**,佔用整個時間片 | **強制休眠**,CPU 空閒可執行其他進程/系統任務 |
| CPU 佔用 (單核、單執行緒遊戲迴路) | **100%** (因無其他執行緒競爭,yield 即歸還即搶回) | **<10%** (大部分時間在休眠,CPU 獲釋放) |
| 響應延遲 | 極低 (微秒級) | ~1ms (受系統時鐘精度影響) |
// 將所有 Thread.yield() 替換為 Thread.sleep(1)
Thread.sleep(1); // 原 Thread.yield();
Thread.yield() 可緩解卡頓。Thread.sleep(1) 可能同樣有效,甚至更佳——強制讓出 CPU 讓系統處理按鍵中斷、GC 等高優先級任務。Thread.sleep(frameTime) 固定幀率 (如 30FPS → sleep(33)),而非 yield。Thread.yield(),但必須有其他就緒執行緒 (如專門的事件分發執行緒) 才能真正讓出 CPU。sleep(1) 或 sleep(0) (視 JVM 實現),避免空轉燒盡電池。LockSupport.parkNanos、Phaser、CountDownLatch 等更精確的同步原語。Thread.yield() 是「禮貌建議」,Thread.sleep() 是「強制休假」。單執行緒計算密集迴路中,yield 形同虛設,sleep 才能真正讓 CPU 降溫、省電。記住:**沒有睡眠的迴路,就是在燒錢**。