60 秒回答模板

可以从内置锁和显式锁两大类回答。synchronized 是 JVM 内置监视器锁,进入同步代码块或方法时自动加锁,退出或异常时自动释放,支持可重入和 wait/notify;ReentrantLock 是 JUC 显式锁,支持可重入、tryLock、可中断等待、公平锁选项和多个 Condition;ReadWriteLock 把读锁和写锁分开,适合读多写少场景,允许多个读线程并发但写线程互斥;StampedLock 提供乐观读、悲观读和写锁,性能潜力高但不可重入且使用更复杂;Atomic 类和 CAS 适合简单状态更新,避免阻塞但要处理自旋和 ABA 等问题。实际选择要看临界区大小、竞争强度、读写比例、是否需要超时和中断、是否需要条件队列以及代码可维护性。

考点 自动与显式
难度 真实面经高频题
回答目标 讲清机制、边界和追问

深入解析

01

synchronized 内置锁

synchronized 是 Java 语言级同步机制,可以修饰实例方法、静态方法或代码块。它基于对象监视器实现互斥,同一线程可以重入,退出同步块或抛异常时自动释放锁。优点是语义简单、不会忘记 unlock,JVM 对它有大量优化;限制是灵活性较弱,不能显式尝试获取、不能设置公平性,也不能像 ReentrantLock 那样拥有多个条件队列。

02

ReentrantLock 显式锁

ReentrantLock 是 JUC 中最常用的显式互斥锁,底层依赖 AQS。它和 synchronized 一样可重入,但提供更多控制能力,例如 tryLock 立即失败、带超时等待、lockInterruptibly 响应中断、公平锁或非公平锁选择,以及多个 Condition。代价是必须在 finally 中 unlock,否则异常路径容易造成死锁。它适合需要可中断、限时等待或复杂条件队列的场景。

03

读写锁

ReadWriteLock 典型实现是 ReentrantReadWriteLock,读锁共享、写锁独占。多个读线程可以同时进入,写线程进入时需要排斥其他读写线程,适合读多写少、读操作耗时明显且写操作不频繁的共享数据结构。它并不总是更快,如果写多、读临界区很短或锁竞争不明显,读写锁的维护成本可能超过收益。还要注意锁降级、写锁饥饿和缓存一致性问题。

04

StampedLock 与乐观读

StampedLock 提供写锁、悲观读锁和乐观读。乐观读不会阻塞写线程,而是先读取数据,再用 stamp 校验期间是否发生写入;如果校验失败,再退化为悲观读锁。它适合读非常多、写较少且读取可重试的场景。但 StampedLock 不可重入,使用不当容易死锁;stamp 需要正确保存和校验,代码复杂度高,因此更适合性能敏感且团队能驾驭的局部模块。

05

CAS 和同步器

AtomicInteger、AtomicReference、LongAdder 等基于 CAS 或分段累加思想,适合简单计数、状态切换和引用更新。它们不是传统阻塞锁,但能在低到中等竞争下减少上下文切换。JUC 里还有 Semaphore、CountDownLatch、CyclicBarrier、Phaser 等同步器,它们解决的是许可控制、等待多个任务完成或阶段协作,不一定是互斥锁。选择机制时要先明确是在保护临界区、协调线程,还是做无锁状态更新。

易错点

  • 只罗列锁名称,不说明互斥、可重入、公平、可中断和条件等待等差异。
  • 认为 ReentrantLock 一定比 synchronized 性能好,忽略现代 JVM 对 synchronized 的优化和场景差异。
  • 使用 ReentrantLock 时没有在 finally 中 unlock,异常路径可能导致死锁。
  • 在写多或临界区很短的场景滥用读写锁,反而增加复杂度和开销。

面试官追问

synchronized 和 ReentrantLock 怎么选?

普通互斥优先 synchronized,语义简单且自动释放。需要 tryLock、超时、可中断、公平性或多个 Condition 时,再选择 ReentrantLock。

ReadWriteLock 一定比互斥锁快吗?

不一定。只有读多写少、读操作耗时较明显、竞争存在时才可能收益明显。写多或临界区很短时,读写锁的管理成本可能更高。

CAS 算不算锁?

CAS 不是传统阻塞锁,它通过原子比较交换更新共享状态,失败时通常重试。它适合简单状态更新,但高竞争下会自旋消耗 CPU,也要注意 ABA 等问题。

Condition 和 wait/notify 有什么区别?

wait/notify 依赖 synchronized 的对象监视器,一个对象对应一个等待集合;Condition 依赖 Lock,一个 Lock 可以创建多个 Condition,使不同等待条件分队列管理。