在 java 的 synchronized 代码块中调用 thread.sleep() 不会释放锁。线程会持有该对象的监视器(monitor)并进入阻塞状态,直到睡眠时间结束或被打断,期间其他尝试获取同一把锁的线程将被阻塞。

为什么 sleep 不释放锁而 wait 会?
这是因为 synchronized 是 JVM 层面的内置锁机制,而 sleep() 只是让当前线程暂停执行,并不涉及锁状态的变更。相比之下,Object.wait() 是专门设计用于释放锁并等待通知的方法。当线程调用 wait() 时,它会释放持有的对象锁,进入等待集,允许其他线程获取锁并修改共享状态。

public class LockTest {
private final Object lock = new Object();
public void methodWithSleep() {
synchronized (lock) {
System.out.println("Start sleep, holding lock");
try {
Thread.sleep(5000); // 持有锁休眠5秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("End sleep, still holding lock");
}
}
public void methodWithWait() {
synchronized (lock) {
System.out.println("Start wait, releasing lock");
try {
lock.wait(5000); // 释放锁等待5秒
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("End wait, re-acquired lock");
}
}
}
上述代码展示了两种行为:在 methodWithSleep 中,其他线程在 5 秒内无法进入任何同步 lock 的代码块;而在 methodWithWait 中,其他线程可以立即获取 lock 并执行其同步逻辑。
如果在 sleep 期间发生异常会怎样?
如果 sleep() 被中断抛出 InterruptedException,当前线程仍然持有锁。开发者必须在捕获异常后决定是否继续持有锁或提前退出同步块。若未处理异常直接抛出,锁会在栈 unwind 过程中由 JVM 自动释放,但此时可能处于不一致状态。

public void riskyMethod() {
synchronized (lock) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 锁依然持有!
System.out.println("Interrupted but still holding lock");
// 错误做法:直接返回可能导致后续逻辑无锁运行
// return;
}
// 正常完成,锁在此处释放
}
}
因此,最佳实践是在 catch 块中恢复中断状态(Thread.currentThread().interrupt()),并根据业务逻辑决定是重试、清理资源还是安全退出。切勿在持有锁的情况下进行长时间阻塞操作,除非你明确知道其他线程不需要访问同一资源。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











