一句话定位两者都是 Java 的单机锁非分布式锁用于保证单机并发安全。 核心差异可以归到一点 ——synchronized 是 JVM 内置关键字ReentrantLock 是基于 AQS 实现的 JDK 类后者的所有灵活性都来自自己管理队列。一、快速对比表维度synchronizedReentrantLock层面JVM 内置关键字monitorenter/exitJDK 类基于AQS实现可重入✅ Mark Word 计数器 1✅ AQS 的state1公平锁仅非公平可选公平/非公平构造传boolean释放锁自动释放出同步块/异常必须手动unlock()放在finally可中断❌ 抢不到只能死等✅lockInterruptibly()超时获取❌✅tryLock(timeout)非阻塞尝试❌✅tryLock()条件等待单一wait/notify队列多个Condition精确唤醒锁升级✅ 偏向→轻量级→重量级无此机制二、AQS理解一切的地基AQSAbstractQueuedSynchronizer抽象队列同步器是 JUC 包里几乎所有锁的底层ReentrantLock、Semaphore、CountDownLatch…。它只有两个核心零件一个int state记录锁状态。0 空闲1 被持有2 重入一次……对它的修改用CAS比较并交换原子操作保证线程安全。一个等待队列CLH 双向链表抢不到锁的线程被包装成 Node 入队并park挂起阻塞、不占 CPU持有者释放锁时唤醒队头节点来抢。运行流程抢锁 → CAS 改 state(0→1) 成功 → 持有锁 失败 → 包装成 Node 进队列 → park 挂起排队 释放 → state 改回 0 → 唤醒队头节点(unpark) → 它 CAS 抢锁、出队公平 vs 非公平的区别就在抢锁前要不要先看队列里有没有人排队公平锁要看、老实排队非公平锁直接 CAS 插队抢抢不到再排队吞吐更高是默认。三、ReentrantLock 多出的三种能力都源于 AQS 队列1. 可中断 / 超时 / 非阻塞 —— 排队时能灵活退出synchronized 一旦没抢到就只能死等ReentrantLock 在 park 前后会检查是否被中断是否超时于是支持lockInterruptibly()排队挂起时可被interrupt唤醒放弃 —— 可用于打破死锁。tryLock(2, SECONDS)最多等 2 秒超时返回false去做降级逻辑。tryLock()试一下拿不到立即返回false绝不排队。if (lock.tryLock(2, TimeUnit.SECONDS)) { try { /* 干活 */ } finally { lock.unlock(); } // 必须手动释放 } else { /* 没抢到执行降级 */ }2. Condition 条件变量 —— 精确唤醒synchronized的wait/notify只有一个等待队列大通铺notifyAll会把无关线程一起吵醒再睡回去浪费一轮 ——唤醒粒度粗。ReentrantLock可创建多个Condition每个是独立的等待队列小房间唤醒谁只动谁。经典的生产者-消费者Condition notFull lock.newCondition(); // 等有空位 Condition notEmpty lock.newCondition(); // 等有数据 // 生产者满了: notFull.await(); 消费者取走后: notFull.signal(); // 消费者空了: notEmpty.await(); 生产者放入后: notEmpty.signal();生产者与消费者各睡各的等待区互不打扰这就是精确唤醒 / 唤醒粒度细。对照记忆wait/notify 一个大通铺喊一嗓子全醒Condition 多个小房间敲哪屋只醒哪屋。底层每个 Condition 也维护一条条件队列signal就是把节点转移回主锁队列去抢锁 ——还是那套队列机制。四、synchronized 的锁升级补充JDK 1.6 后引入升级不可逆无锁 → 偏向锁 → 轻量级锁(CAS自旋) → 重量级锁(Monitor)重量级锁对应ObjectMonitornative / C 实现底层依赖操作系统 mutex开销大。 注意JDK 15 起偏向锁已默认禁用JEP 374。五、一句话总结ReentrantLock 比 synchronized 多出的灵活性本质都来自它基于 AQS 自己管理队列因此能在排队时响应中断、支持超时、可 tryLock还能用多个 Condition 实现精确唤醒代价是必须手动finally释放。而 synchronized 是 JVM 内置、自动释放、有锁升级优化写法更简单。
synchronized 与 ReentrantLock 的区别(AQS)
发布时间:2026/6/30 8:07:11
一句话定位两者都是 Java 的单机锁非分布式锁用于保证单机并发安全。 核心差异可以归到一点 ——synchronized 是 JVM 内置关键字ReentrantLock 是基于 AQS 实现的 JDK 类后者的所有灵活性都来自自己管理队列。一、快速对比表维度synchronizedReentrantLock层面JVM 内置关键字monitorenter/exitJDK 类基于AQS实现可重入✅ Mark Word 计数器 1✅ AQS 的state1公平锁仅非公平可选公平/非公平构造传boolean释放锁自动释放出同步块/异常必须手动unlock()放在finally可中断❌ 抢不到只能死等✅lockInterruptibly()超时获取❌✅tryLock(timeout)非阻塞尝试❌✅tryLock()条件等待单一wait/notify队列多个Condition精确唤醒锁升级✅ 偏向→轻量级→重量级无此机制二、AQS理解一切的地基AQSAbstractQueuedSynchronizer抽象队列同步器是 JUC 包里几乎所有锁的底层ReentrantLock、Semaphore、CountDownLatch…。它只有两个核心零件一个int state记录锁状态。0 空闲1 被持有2 重入一次……对它的修改用CAS比较并交换原子操作保证线程安全。一个等待队列CLH 双向链表抢不到锁的线程被包装成 Node 入队并park挂起阻塞、不占 CPU持有者释放锁时唤醒队头节点来抢。运行流程抢锁 → CAS 改 state(0→1) 成功 → 持有锁 失败 → 包装成 Node 进队列 → park 挂起排队 释放 → state 改回 0 → 唤醒队头节点(unpark) → 它 CAS 抢锁、出队公平 vs 非公平的区别就在抢锁前要不要先看队列里有没有人排队公平锁要看、老实排队非公平锁直接 CAS 插队抢抢不到再排队吞吐更高是默认。三、ReentrantLock 多出的三种能力都源于 AQS 队列1. 可中断 / 超时 / 非阻塞 —— 排队时能灵活退出synchronized 一旦没抢到就只能死等ReentrantLock 在 park 前后会检查是否被中断是否超时于是支持lockInterruptibly()排队挂起时可被interrupt唤醒放弃 —— 可用于打破死锁。tryLock(2, SECONDS)最多等 2 秒超时返回false去做降级逻辑。tryLock()试一下拿不到立即返回false绝不排队。if (lock.tryLock(2, TimeUnit.SECONDS)) { try { /* 干活 */ } finally { lock.unlock(); } // 必须手动释放 } else { /* 没抢到执行降级 */ }2. Condition 条件变量 —— 精确唤醒synchronized的wait/notify只有一个等待队列大通铺notifyAll会把无关线程一起吵醒再睡回去浪费一轮 ——唤醒粒度粗。ReentrantLock可创建多个Condition每个是独立的等待队列小房间唤醒谁只动谁。经典的生产者-消费者Condition notFull lock.newCondition(); // 等有空位 Condition notEmpty lock.newCondition(); // 等有数据 // 生产者满了: notFull.await(); 消费者取走后: notFull.signal(); // 消费者空了: notEmpty.await(); 生产者放入后: notEmpty.signal();生产者与消费者各睡各的等待区互不打扰这就是精确唤醒 / 唤醒粒度细。对照记忆wait/notify 一个大通铺喊一嗓子全醒Condition 多个小房间敲哪屋只醒哪屋。底层每个 Condition 也维护一条条件队列signal就是把节点转移回主锁队列去抢锁 ——还是那套队列机制。四、synchronized 的锁升级补充JDK 1.6 后引入升级不可逆无锁 → 偏向锁 → 轻量级锁(CAS自旋) → 重量级锁(Monitor)重量级锁对应ObjectMonitornative / C 实现底层依赖操作系统 mutex开销大。 注意JDK 15 起偏向锁已默认禁用JEP 374。五、一句话总结ReentrantLock 比 synchronized 多出的灵活性本质都来自它基于 AQS 自己管理队列因此能在排队时响应中断、支持超时、可 tryLock还能用多个 Condition 实现精确唤醒代价是必须手动finally释放。而 synchronized 是 JVM 内置、自动释放、有锁升级优化写法更简单。