Thread.yield() 是一個常被誤解的線程協作方法。本文通過源碼語義分析與實戰代碼驗證,釐清其「不釋放鎖」「可能立即重新調度」等關鍵特性。
synchronized 鎁定的對象鎖)。public class YieldDemo {
static int shareVar = 0;
static class TestThread extends Thread {
public TestThread(String name) { super(name); }
@Override
public synchronized void run() { // 實例鎖
for (int i = 0; i < 4; i++) {
System.out.println(getName() + " : " + i);
Thread.yield(); // 關鍵點
}
}
}
public static void main(String[] args) {
TestThread t1 = new TestThread("t1");
TestThread t2 = new TestThread("t2");
// 情況 A:啟動同一實例兩次(非法,僅演示鎖行為)
// t1.start(); t1.start(); // IllegalThreadStateException
// 情況 B:兩個不同實例,共享同步方法鎖(this 不同,故無鎖競爭)
// 為驗證鎖,需共享同一鎖對象 → 改用 static synchronized 或顯式鎖
}
}
static class LockThread extends Thread {
private static final Object LOCK = new Object();
public LockThread(String name) { super(name); }
@Override
public void run() {
synchronized (LOCK) { // 共享類級鎖
for (int i = 0; i < 4; i++) {
System.out.println(getName() + " : " + i);
Thread.yield();
}
}
}
}
public static void main(String[] args) {
new LockThread("T1").start();
new LockThread("T2").start();
}
T1 : 0
T1 : 1
T1 : 2
T1 : 3
T2 : 0
T2 : 1
T2 : 2
T2 : 3
結論:T1 持有鎖期間多次 yield(),T2 無法獲得鎖,只能等待 T1 釋放鎖(循環結束退出 synchronized 塊)後才能運行。證明 yield() 不釋放鎖。
若去掉 synchronized 或使用不同鎖對象,兩線程無鎖競爭:
// 無鎖版本
static class NoLockThread extends Thread {
public NoLockThread(String name) { super(name); }
@Override public void run() {
for (int i = 0; i < 4; i++) {
System.out.println(getName() + " : " + i);
Thread.yield();
}
}
}
T1 : 0
T1 : 1
T2 : 0
T1 : 2
T2 : 1
T1 : 3
T2 : 2
T2 : 3
也可能輸出連續執行(視調度器策略、CPU 核心數、負載而定)。
yield() 多為畫蛇添足。LockSupport.parkNanos() / Condition.await()。thread.setPriority(Thread.MIN_PRIORITY)(慎用)。ReentrantLock(true) 公平鎖。Thread.yield() 是「禮貌提示」而非「強制讓步」:不釋放鎖、不進入阻塞、調度結果不可預期。生產代碼中幾乎無正當理由直接調用,理解其語義僅為面試與底層診斷服務。