| 誤區 | 真相 |
| yield() 等同於 sleep(0) | sleep(0) 觸發上下文切換並進入 TIMED_WAITING,yield() 僅提示調度器,不保證切換。 |
| 可用於實現線程協作/同步 | 極不可靠,必須使用 wait/notify、Lock/Condition、CountDownLatch 等正規同步原語。 |
| 能降低 CPU 佔用 | 若就緒隊列只有當前線程,yield() 後立即繼續執行,形成忙等待,反而浪費 CPU。 |
| 可保證公平性 | 無公平性保證,調度器可能連續選中同一線程。 |
源碼視角
// JDK 17 Thread.yield()
@IntrinsicCandidate
public static native void yield(); // 本地方法,委託 JVM -> OS 調度器
// JVM 實現邏輯 (簡化)
void Thread::yield() {
if (Thread::current()->is_Java_thread()) {
JavaThread* jt = (JavaThread*)Thread::current();
// 提示調度器:當前線程願意讓出 CPU
os::yield(); // 平台相關: Windows -> SwitchToThread(); Linux -> sched_yield();
}
}
什麼時候「可能」有用?
- 長時間計算循環中主動讓步:防止獨佔 CPU 導致同優先級其他線程飢餓 (如視頻渲染、大數據排序)。
- 測試併發代碼覆蓋率:在關鍵路徑插入 yield() 增加線程交錯機率,暴露競態條件。
- 協作式多任務框架內部:某些用戶態線程庫 (如 Quasar、早期 Greenlets) 依賴 yield 實現調度。
正確替代方案
| 需求 | 推薦方案 |
| 定時讓出 CPU | Thread.sleep(1) (進入 TIMED_WAITING,確保切換) |
| 等待條件滿足 | LockSupport.parkNanos / Condition.await / CountDownLatch |
| 降低優先級 | thread.setPriority(Thread.MIN_PRIORITY) (謹慎使用,可能導致飢餓) |
| CPU 密集型任務分片 | 拆分為小任務提交給 ForkJoinPool 或自定義線程池 |
基準測試:yield vs sleep(1)
public class YieldBenchmark {
static volatile long yieldCount = 0, sleepCount = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10_000_000; i++) Thread.yield();
yieldCount = System.nanoTime();
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10_000_000; i++) {
try { Thread.sleep(0, 1); } catch (InterruptedException ignored) {}
}
sleepCount = System.nanoTime();
});
t1.start(); t2.start();
t1.join(); t2.join();
System.out.println("yield 耗時: " + (yieldCount - System.nanoTime()) / 1e6 + " ms");
System.out.println("sleep 耗時: " + (sleepCount - System.nanoTime()) / 1e6 + " ms");
}
}
// 典型結果: yield ~幾百 ms (極快,幾乎未切換) | sleep ~數十秒 (真實切換開銷)
總結
Thread.yield() 是一個「良好的願望」,而非「強制的命令」。在現代預emptive 調度器與多核 CPU 下,它幾乎沒有可預測的實際效果。業務代碼中請勿使用 yield() 進行同步或流控。若需主動讓出 CPU,請使用 Thread.sleep(1) 或正規同步工具;若需測試併發交錯,可在測試代碼中輔助使用。理解其本質,避免濫用,是並發編程成熟的標誌。
- 上一篇文章: Java 多線程入門核心知識體系:創建方式、線程池、同步機制與避坑指南
- 下一篇文章: Hibernate 一對多雙向關聯映射完整實戰:注解與 XML 雙配置、級聯操作、避坑指南
Copyright ©
程式碼之家 All Rights Reserved