
一句话synchronized早就不是重量级锁了。JDK6 引入了锁升级机制偏向锁 → 轻量级锁 → 重量级锁大部分情况下只到轻量级锁自旋性能和ReentrantLock差不多。95% 场景用 synchronized 就够了。synchronized 锁升级过程无锁状态 ↓ 第一个线程来竞争 偏向锁只记录线程 IDCAS 一次搞定 ↓ 第二个线程来竞争 轻量级锁自旋等待不阻塞 ↓ 自旋超过一定次数 重量级锁OS 互斥锁线程阻塞/唤醒偏向锁适用场景只有一个线程反复加同一把锁比如StringBuffer只被一个线程操作。原理 JVM 在对象头里记录当前持有锁的线程 ID 下次同一个线程再来加锁 → 检查 ID 一致 → 直接通过零开销 相当于VIP 通道因为大部分锁实际上只有一个线程在用JDK15 开始默认关闭偏向锁-XX:-UseBiasedLocking因为现代并发场景下偏向锁维护成本 收益。面试提到这个加分。轻量级锁适用场景两个线程交替使用同一把锁竞争不激烈。原理 在线程栈帧里创建 Lock RecordCAS 把对象头指向 Lock Record 另一个线程发现锁被占了 → 不阻塞而是自旋空转等着 像打电话占线 → 不挂断每隔几秒重拨一次 自旋一定次数后还拿不到 → 升级为重量级锁重量级锁适用场景多线程激烈竞争。原理 依赖操作系统层面的互斥锁mutex 线程拿不到锁 → 进入阻塞状态 → 涉及用户态↔内核态切换 这个切换非常昂贵微秒级为什么说 synchronized 不重了锁升级的核心思路用最轻的方式解决问题 只有一个线程 → 偏向锁几乎零开销 两个线程交替 → 轻量级锁自旋比阻塞轻得多 真正激烈竞争 → 重量级锁最后手段 大部分实际场景停留在轻量级锁阶段根本到不了重量级锁。 所以 synchronized 太重这个说法在 JDK6 之后就不成立了。synchronized vs ReentrantLock维度synchronizedReentrantLock本质JVM 内置关键字java.util.concurrent 包的类基于 AQS锁释放自动出作用域释放必须手动unlock()finally 中可中断不行等锁时只能傻等lockInterruptibly()可响应中断公平锁只支持非公平支持公平 / 非公平条件变量只有一组wait()/notify()多个Conditionawait/signal尝试加锁不支持tryLock(timeout)超时放弃锁升级有偏向 → 轻量 → 重量无此机制性能JDK6 差距很小高竞争下略优ReentrantLock 底层AQSReentrantLock 内部继承 AQSAbstractQueuedSynchronizer AQS 核心设计 state 变量int0未锁定0锁定次数ReentrantLock 可重入 CLH 双向队列排队的线程链表 加锁流程 ① CAS 尝试把 state 从 0 改为 1 ② 成功 → 拿到锁 ③ 失败 → 当前线程封装成 Node 入 CLH 队列 → 阻塞等待 ④ 前一个线程释放锁 → unpark 队列中下一个线程 → 唤醒 公平 vs 非公平 非公平锁默认新线程先 CAS 抢抢不到再排队 → 吞吐量更高 公平锁严格按 CLH 队列顺序来 → 不饥饿但吞吐量低面试追问“AQS 除了 ReentrantLock 还被谁用了” →Semaphore信号量、CountDownLatch、ReentrantReadWriteLock都基于 AQS。标准写法对比synchronized// 简洁自动释放不会忘publicsynchronizedvoidtransfer(Accounttarget,intamount){this.balance-amount;target.balanceamount;}ReentrantLock// 必须手动释放忘记就死锁privatefinalReentrantLocklocknewReentrantLock();publicvoidtransfer(Accounttarget,intamount){lock.lock();try{this.balance-amount;target.balanceamount;}finally{lock.unlock();// 必须在 finally 里}} 面试回答模板synchronized 和 ReentrantLock 的区别我从五个维度来说 第一锁释放方式不同 synchronized 是 JVM 关键字出作用域自动释放 ReentrantLock 是 API 层面的必须手动在 finally 中 unlock。 第二可中断性不同 synchronized 等锁时不能中断只能一直等 ReentrantLock 可以用 lockInterruptibly 响应中断。 第三条件变量不同 synchronized 只有一组 wait/notify ReentrantLock 支持多个 Condition可以做更精细的线程通信。 第四锁的公平性 synchronized 只支持非公平锁 ReentrantLock 可以选择公平锁或非公平锁。 第五尝试加锁 synchronized 不支持ReentrantLock 可以 tryLock 设置超时。 不过有一点要纠正——synchronized 不是重量级锁。 JDK6 之后有锁升级机制偏向锁 → 轻量级锁 → 重量级锁 大部分情况只到轻量级锁性能差距很小。 所以 95% 场景用 synchronized 就够了 需要灵活控制中断、超时、多条件时才用 ReentrantLock。参考来源《Java 并发编程的艺术》第 2 章JDK8java.util.concurrent.locks.ReentrantLock源码JDK8AbstractQueuedSynchronizer源码