synchronized不能中断等待线程,因其底层monitor不响应interrupt信号;而ReentrantLock的lockInterruptibly()可响应中断并抛出InterruptedException。
synchronized 是 JVM 层的内置锁,进入阻塞状态后线程会挂起,且无法被 Thread.interrupt() 中断。这是由底层 monitor 实现决定的——它不响应中断信号,只会一直等锁释放。
而 Lock 接口(如 ReentrantLock)提供了 lockInterruptibly() 方法,调用时若线程被中断,会抛出 InterruptedException 并立即退出等待队列。
synchronized 时,即使调用 thread.interrupt(),线程仍卡在 monitorenter 指令上,无法响应ReentrantLock.lockInterruptibly() 在获取锁前会检查中断状态,适合需要超时或可取消的场景(如任务调度、RPC 调用)lockInterruptibly() 不是“自动中断”,必须配合外部中断逻辑(比如另一个线程调用 interrupt())synchronized 块内可以安全使用 Object.wait() / notify(),因为它们绑定的是同一个 monitor 对象;但 Lock 不提供原生的等待/唤醒机制,必须搭配 Condition 使用。
直接在 ReentrantLock 保护的代码里调用 wait() 会抛 IllegalMonitorStateException,因为此时线程并未持有该对象的 monitor 锁。
synchronized(obj) { obj.wait(); } 合法,obj 就是 monitorlock.lock(); obj.wait(); 非法,obj 和锁无关Condition condition = lock.newCondition(); condition.await(); condition.signal();
Lock 可创建多个 Condition,实现更精细的等待队列(比如读写锁中分别管理读等待和写等待)synchronized 始终是非公平的,且无法配置;ReentrantLock 默认也是非公平,但构造时传 true 可启用公平模式:new ReentrantLock(true)。
公平锁会按线程入队顺序分配锁,避免饥饿,但吞吐量明显下降——每次加锁都要遍历同步队列确认头节点,还可能引发频繁的线程挂起/唤醒切换。
synchronized 经过 JIT 优化后,在无竞争或轻度竞争时几乎无额外开销;而 ReentrantLock 即使未争抢,也有对象创建和方法调用成本JVM 对 synchronized 做了多层优化:偏向锁 → 轻量级锁 → 重量级锁。一旦发生锁竞争(比如两个线程同时进入同一把锁),偏向锁会被撤销,后续再进入就会直接走轻量级锁路径;若自旋失败(默认 10 次),就膨胀为重量级锁,线程进入操作系统 Mutex 等待。
这个过程不可逆,且撤销偏向锁需全局安全点(stop-the-world),可能造成明显停顿。
ReentrantLock 没有这种“锁升级”概念,始终基于 AQS 队列,行为稳定可预期-XX:-UseBiasedLocking)来规避撤销开销,尤其在容器环境或短生命周期应用中public class LockVsSyncExample {
private final Object syncObj = new Object();
private final ReentrantLock lock = new ReentrantLock();
public void syncMethod() {
synchronized (syncObj) {
// 正确:wait 必须在 synchronize
d 块中
try {
syncObj.wait(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public void lockMethod() {
lock.lock();
try {
// 错误:不能在这里调用 wait()
// syncObj.wait(); // 抛 IllegalMonitorStateException
// 正确:用 Condition
Condition condition = lock.newCondition();
condition.await(100, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
}
锁的语义一致性比语法糖更重要。很多人以为 ReentrantLock 就是 synchronized 的升级版,其实它们适用边界很不同:前者适合需要中断、超时、多条件等待的显式控制场景;后者在大多数简单同步需求中更轻量、更不易出错。真正容易被忽略的是——synchronized 的 monitor 本质决定了它和 JVM 内存模型、GC 安全点、逃逸分析深度耦合,而这些细节在调试死锁或性能抖动时才突然变得关键。