Thread.sleep 会释放 CPU 但不释放锁,适用于纯延迟场景;在 synchronized 块内调用会导致锁持有时间延长,应移至块外;与 wait()(释放锁、需同步上下文)和 park()(不释放锁、底层使用)语义不同。

Thread.sleep 会释放 CPU,但不会释放锁 —— 这是绝大多数人误用它的根本原因。
Thread.sleep 的作用和真实行为
Thread.sleep 让当前线程暂停执行指定毫秒数,期间线程状态变为 TIMED_WAITING,JVM 会将其从 CPU 调度队列中移除,从而真正释放 CPU 资源。但它完全不涉及同步机制:如果线程正持有 synchronized 锁或 ReentrantLock,休眠期间锁依然被牢牢占着。
- 适合场景:纯粹的“等一会儿”,比如轮询间隔、模拟延迟、防止过快重试
- 不适合场景:想让其他线程趁机获取锁并执行临界区代码(这时该用
wait()) - 注意:
Thread.sleep(0)并非无操作,它会触发一次线程调度让出 CPU 时间片,但不保证切换到哪个线程
常见错误:在 synchronized 块里 sleep 导致死锁或吞吐暴跌
典型反模式:synchronized(obj) { ... Thread.sleep(1000); ... }。此时其他线程即使满足条件,也得干等这一秒才能进入同步块 —— 休眠成了“锁持有时间延长器”。
- 修复思路:把
sleep移到同步块外,只在必要时加锁 - 示例对比:
// ❌ 错误:锁被霸占 1 秒 synchronized(lock) { doWork(); Thread.sleep(1000); // 其他线程卡住 }// ✅ 正确:锁只保护关键操作 synchronized(lock) { doWork(); } Thread.sleep(1000); // CPU 释放,锁已释放
替代方案选型:sleep / wait / LockSupport.park 的核心区别
三者都让线程暂停,但语义和使用约束完全不同:
-
Thread.sleep(long):无需任何前提,任意线程可调用;不可被interrupt()中断(会抛InterruptedException,但不是“立即唤醒”) -
obj.wait():必须在synchronized(obj)块内调用;会释放obj上的锁;可被notify()或中断唤醒 -
LockSupport.parkNanos():基于Unsafe,不依赖锁对象;不释放任何锁;响应中断但不抛异常,需手动检查Thread.interrupted()
简单记:要“等固定时间且不管锁”,用 sleep;要“等某个条件成立且愿放手让别人抢锁”,用 wait;写并发框架底层才碰 park。
容易忽略的细节:中断处理与精度偏差
Thread.sleep 可能被中断,且实际休眠时间受系统定时器精度影响(Windows 通常 15ms,Linux 可达 1ms)。不处理中断会导致线程无法响应关闭信号。
- 必须捕获
InterruptedException,且通常应恢复中断状态:Thread.currentThread().interrupt(); - 不要用
sleep实现高精度定时(如音频同步),改用System.nanoTime()+ 自旋或ScheduledExecutorService - 避免大数值休眠(如
sleep(Long.MAX_VALUE)),可能因溢出转成负数导致立即返回
真正难的从来不是“怎么睡”,而是“睡的时候别锁门,醒了还得听得见叫醒声”。










