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

Java 線程 sleep() 與 wait() 核心差異深度解析:鎖行為、調度原理與實戰場景

     編輯:Java 程式設計入門

核心差異速查表

維度Thread.sleep()Object.wait()
所屬類Thread (靜態方法)Object (實例方法)
鎖行為不釋放鎖釋放鎖
調用前提任意代碼位置必須在 synchronized 塊/方法中
喚醒方式時間到期 / interrupt()notify()/notifyAll() / interrupt() / 時間到期
異常處理必須 catch InterruptedException必須 catch InterruptedException
虛假喚醒無可能發生,需循環檢查條件

睡眠不釋放鎖:實證代碼


public class SleepHoldLock {
    private static final Object LOCK = new Object();
    
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (LOCK) {
                System.out.println("Thread-A 持有鎖,睡眠 3 秒");
                try { Thread.sleep(3000); } catch (InterruptedException ignored) {}
                System.out.println("Thread-A 醒來,釋放鎖");
            }
        }, "Thread-A").start();
        
        // 確保 Thread-A 先獲取鎖
        try { Thread.sleep(100); } catch (InterruptedException ignored) {}
        
        new Thread(() -> {
            System.out.println("Thread-B 嘗試獲取鎖...");
            synchronized (LOCK) {
                System.out.println("Thread-B 獲取到鎖"); // 3 秒後才會打印
            }
        }, "Thread-B").start();
    }
}

輸出證明:Thread-B 在 Thread-A sleep 期間無法獲取鎖,處於阻塞狀態。

等待釋放鎖:實證代碼


public class WaitReleaseLock {
    private static final Object LOCK = new Object();
    
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (LOCK) {
                System.out.println("Thread-A 持有鎖,wait 3 秒");
                try { LOCK.wait(3000); } catch (InterruptedException ignored) {}
                System.out.println("Thread-A 醒來,繼續持有鎖");
            }
        }, "Thread-A").start();
        
        try { Thread.sleep(100); } catch (InterruptedException ignored) {}
        
        new Thread(() -> {
            System.out.println("Thread-B 嘗試獲取鎖...");
            synchronized (LOCK) {
                System.out.println("Thread-B 立即獲取到鎖"); // 立即打印!
                try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
                System.out.println("Thread-B 釋放鎖");
            }
        }, "Thread-B").start();
    }
}

輸出證明:Thread-A wait() 釋放鎖,Thread-B 立即獲取鎖 執行。

interrupt() 打斷機制統一性


// 打斷睡眠
Thread t1 = new Thread(() -> {
    try { Thread.sleep(10000); } catch (InterruptedException e) { 
        System.out.println("睡眠被打斷"); 
        return; // 安全退出
    }
});
t1.start();
Thread.sleep(100);
t1.interrupt(); // 拋出 InterruptedException

// 打斷等待
Thread t2 = new Thread(() -> {
    synchronized (LOCK) {
        try { LOCK.wait(10000); } catch (InterruptedException e) {
            System.out.println("等待被打斷");
            return;
        }
    }
});
t2.start();
Thread.sleep(100);
t2.interrupt(); // 拋出 InterruptedException

關鍵點:

  • interrupt() 只設置中斷標誌,不直接拋出異常
  • 線程在 sleep/wait/join 時檢測到標誌 → 拋出 InterruptedException 並清除標誌
  • 線程運行普通代碼時調用 interrupt() → 標誌置位,不拋異常,需自行檢查 Thread.interrupted()

正確的等待模式:條件循環


// 錯誤:單次 wait,虛假喚醒導致邏輯錯誤
synchronized (lock) {
    lock.wait();
    doSomething(); // 可能條件未滿足就執行
}

// 正確:循環檢查條件
synchronized (lock) {
    while (!condition) {
        lock.wait();
    }
    doSomething(); // 條件確實滿足
}

現實類比:火車站買票

  • sleep 模式:站在窗口前干等,售票員出票前你佔用窗口資源,後面人無法辦理
  • wait 模式:拿到號碼去休息區等待(釋放窗口),叫號時回來(重新競爭窗口),效率更高

線程調度補充

  • Java 使用搶佔式調度:高優先級線程可搶佔 CPU
  • 時間片輪轉:同優先級線程輪流執行
  • yield():主動放棄當前時間片,不保證調度結果
  • join():等待目標線程終止,內部調用 wait()

選擇指南

  1. 單純延時、無同步需求 → Thread.sleep()
  2. 多線程協作、條件等待、生產者消費者 → Object.wait()/notify()
  3. 高級併發工具:LockSupport.park()/unpark()、Condition.await()/signal()、CountDownLatch、CyclicBarrier、CompletableFuture
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved