| 維度 | Thread.sleep() | Object.wait() |
|---|---|---|
| 所屬類 | Thread(靜態方法) | Object(實例方法) |
| 核心目的 | 線程暫停/控制執行節奏 | 線程間通信/協作(等待通知機制) |
| 鎖行為 | 不釋放鎖(持有監視器所有權) | 釋放鎖(釋放監視器所有權) |
| 調用前提 | 無特殊要求 | 必須在 synchronized 同步塊/方法中 |
| 喚醒方式 | 時間到期自動喚醒 / interrupt() 中斷 | notify()/notifyAll() 喚醒 / 時間到期 / interrupt() |
| 典型場景 | 定時任務、限流延遲、模擬耗時操作 | 生產者-消費者、線程池任務隊列、狀態等待 |
public static void sleep(long millis) throws InterruptedException
使當前正在執行的線程睡眠(暫時停止執行)指定的毫秒數,受系統計時器和調度器精度影響。線程不會失去任何監視器的所有權。
Thread.currentThread()),不可指定其他線程睡眠public class ClockTask implements Runnable {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println(LocalTime.now() + " 報時");
Thread.sleep(1000); // 每秒執行一次
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢復中斷狀態
break; // 退出循環
}
}
}
}
public final void wait() throws InterruptedException
導致當前線程等待,直到另一線程調用該對象的notify()或notifyAll()。當前線程必須擁有此對象的監視器。線程釋放監視器所有權並等待,直到被喚醒後重新獲取監視器繼續執行。
IllegalMonitorStateExceptionpublic class BoundedBuffer<T> {
private final List<T> buffer = new ArrayList<>();
private final int capacity;
public BoundedBuffer(int capacity) { this.capacity = capacity; }
// 生產者調用
public synchronized void put(T item) throws InterruptedException {
while (buffer.size() == capacity) { // 必須用 while 防虛假喚醒
wait(); // 釋放鎖,等待消費者消費
}
buffer.add(item);
notifyAll(); // 喚醒消費者
}
// 消費者調用
public synchronized T take() throws InterruptedException {
while (buffer.isEmpty()) {
wait(); // 釋放鎖,等待生產者生產
}
T item = buffer.remove(0);
notifyAll(); // 喚醒生產者
return item;
}
}
鎖 = 遙控器,線程 = 家庭成員,共享對象 = 電視機
- sleep():A 拿著遙控器看電視,累了眯 10 分鐘(sleep),遙控器仍在 A 手中,別人換不了台
- wait():A 拿著遙控器,電視機調用 wait(),A交出遙控器(釋放鎖),JVM 調度遙控器給 B 或 C。B 調用 notify() 歸還遙控器給等待隊列中的線程
public class SleepHoldLock {
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 e) {}
System.out.println("Thread-A 醒來釋放鎖");
}
}, "Thread-A").start();
// 稍微延遲啟動 B,確保 A 先獲取鎖
new Thread(() -> {
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock) {
System.out.println("Thread-B 獲取鎖"); // 3 秒後才會打印
}
}, "Thread-B").start();
}
}
public class WaitReleaseLock {
static final Object lock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock) {
System.out.println("Thread-A 獲取鎖,調用 wait()");
try { lock.wait(3000); } catch (InterruptedException e) {}
System.out.println("Thread-A 被喚醒/超時");
}
}, "Thread-A").start();
new Thread(() -> {
try { Thread.sleep(100); } catch (InterruptedException e) {}
synchronized (lock) {
System.out.println("Thread-B 獲取鎖"); // 立即打印!A 已釋放鎖
lock.notify(); // 喚醒 A
}
}, "Thread-B").start();
}
}
Thread.yield() 但更強制。Thread.currentThread().interrupt() 恢復中斷狀態,或拋出運行時異常向上傳播,切勿吞掉異常。實際開發強烈建議使用 java.util.concurrent 高級組件:
ReentrantLock + newCondition() 替代 synchronized/wait/notify,支持多條件隊列、可中斷鎖、公平鎖ArrayBlockingQueue 直接實現生產者-消費者,內部封裝鎖與等待總結:sleep() 是線程「自我管理」(不釋放鎖),wait() 是線程「協作交互」(釋放鎖)。理解監視器(鎖)所有權轉移是掌握多線程協作的鑰匙。實戰中優先用 JUC 組件,底層原理必須精通。