首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 線程協作機制詳解:yield() 讓出 CPU 的行為語義、優先級影響與鎖行為實測

     編輯:Java 綜合教學

Java 線程協作機制詳解:yield() 讓出 CPU 的行為語義、優先級影響與鎖行為實測

一、yield() 核心語義

  • 定義:Thread.yield() 通知當前線程暫停執行,將 CPU 使用權讓給同優先級的其他就緒線程。
  • 非阻塞:線程狀態從 RUNNING → RUNNABLE(就緒),不進入 BLOCKED/WAITING,不釋放持有的鎖。
  • 調度不確定性:不保證 當前線程不會立即被再次調度,也不保證特定線程獲取 CPU。僅是「禮讓」提示,最終由 JVM 線程調度器決定。
  • 優先級影響:只讓給相同優先級線程。高優先級線程不受 yield 直接影響,但調度器傾向於高優先級。

二、代碼實測:基礎 yield 行為

public class ThreadYieldTest {
    static Object lock = new Object();

    public static void main(String[] args) {
        Thread t1 = new Thread(new TaskA(), "Thread-A");
        Thread t2 = new Thread(new TaskB(), "Thread-B");
        t1.setPriority(Thread.MIN_PRIORITY); // 1
        t2.setPriority(Thread.MAX_PRIORITY); // 10
        t1.start();
        t2.start();
    }
}

class TaskA implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            if (i == 3) Thread.yield(); // i=3 時禮讓
            System.out.println(Thread.currentThread().getName() + " 執行 ==> " + i);
        }
    }
}

class TaskB implements Runnable {
    public void run() {
        for (int i = 0; i < 5; i++) {
            if (i == 3) Thread.yield();
            System.out.println(Thread.currentThread().getName() + " 執行 ==> " + i);
        }
    }
}

觀察現象

  1. 情況 1:Thread-A 執行到 i=3 yield,Thread-B 搶佔 CPU 繼續執行。
  2. 情況 2:Thread-A yield 後,調度器仍選中 Thread-A 繼續(同優先級時可能)。
  3. 優先級影響:Thread-B 為 MAX_PRIORITY,整體獲得 CPU 時間片顯著多於 Thread-A,但 yield 瞬間不改變優先級邏輯。

三、yield() 與 synchronized 鎖的關鍵驗證:不釋放鎖

class TaskA implements Runnable {
    public void run() {
        synchronized (ThreadYieldTest.lock) {
            System.out.println("進入線程 " + Thread.currentThread().getName());
            for (int i = 0; i < 5; i++) {
                if (i == 3) Thread.yield();
                System.out.println(Thread.currentThread().getName() + " 執行 ==> " + i);
            }
        }
    }
}
// TaskB 同理,同步塊鎖定同一 lock 對象

實測結果

無論如何重複運行,一個線程必須完全執行完同步塊,另一個線程才能進入。yield() 期間鎖未釋放,其他線程嘗試進入 synchronized 塊會阻塞在 BLOCKED 狀態,而非 RUNNABLE。

四、yield() vs sleep() vs wait() 核心對比

五、實際開發中的適用場景

  • 極少直接使用:現代 JVM 調度器極其智能,手動 yield 往往適得其反。
  • 測試/診斷:人為增加線程切換頻率,暴露並發 Bug(如競態條件)。
  • 協作式多任務框架:某些用戶級線程庫(如早期 Green Threads、協程框架)依賴 yield 實現任務切換。

六、總結

  1. yield() 是禮讓提示,非強制調度,不保證執行順序。
  2. 只影響同優先級線程,高優先級線程不受禮讓約束。
  3. 不釋放鎖,同步塊內 yield 仍持有鎖,其他線程無法進入。
  4. 不進入等待狀態,線程保持 RUNNABLE,隨時可能被再次調度。
  5. 生產代碼中幾乎不應使用,依賴 JVM 調度器即可。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方法釋放鎖線程狀態轉換可指定時間優先級影響
yield()否RUNNING → RUNNABLE否僅同優先級
sleep(ms)否RUNNING → TIMED_WAITING是無
wait()是RUNNING → WAITING可選無