Skip to main content
本章节汇总了面试中常见的通用技术概念,不局限于特定语言或数据库,是考察技术内功的关键考点。

一、并发与锁的设计理念

Q1: 悲观锁 vs 乐观锁(看待冲突的态度)

特性悲观锁 (Pessimistic Lock)乐观锁 (Optimistic Lock)
心态“总有刁民想害朕”(保守)“大家都是好人”(乐观)
做法操作前先上锁,锁死资源全程不加锁,提交时检查版本
实现SELECT ... FOR UPDATEsynchronized版本号机制 (version)、CAS 算法
场景写操作频繁、竞争激烈读操作频繁、竞争较少
生活案例:
  • 悲观锁:进卫生间先锁门。你在里面的时候,外面的人只能等(阻塞)。
  • 乐观锁:Git 代码提交。写代码时不锁文件,push 时检查版本,版本冲突则报错。

Q2: 自旋锁 (Spin Lock)(等待的方式)

自旋锁并不属于某种特定的锁实现,而是一种等待策略
  • 传统互斥锁:如果拿不到锁,线程就挂起(睡觉),等待系统唤醒。
  • 自旋锁:如果拿不到锁,线程不睡觉,而是原地打转(死循环)不停询问:“好了没?好了没?”
优缺点:
  • 优点:避免了线程上下文切换(上下文切换很贵)的开销。如果锁很快就释放了,效率极高。
  • 缺点:如果对方占用时间很长,你会白白浪费 CPU 资源在转圈圈上。
生活案例:
  • 互斥锁:饭店没位子,领个号去逛街,等服务员电话。
  • 自旋锁:卫生间有人,你在门口每隔 10 秒敲一次门询问。

Q3: 可重入锁 (Reentrant Lock)(身份的识别)

指一个线程已经获得了某个锁,它可以再次获取这个锁而不会被自己锁死。
  • 可重入:锁能认出“你是自己人”,直接放行。Java 的 synchronizedReentrantLock 都是可重入的。
  • 不可重入:再次尝试获取锁时会因为之前已经加过锁而导致死锁(自己把自己锁在外面)。
生活案例:
  • 你拿着家里的钥匙开了大门进入院子,内屋的门也需要同样的钥匙。如果你能直接刷卡进去就是可重入;如果系统说“你还没出门不能再进”,那你就被困在院子里(死锁)了。

Q4: 公平锁 vs 非公平锁(排队的规则)

  • 公平锁:排队。严格按先来后到,谁等得久谁拿。
  • 非公平锁:插队。锁一释放,新来的人如果正好赶上,可以直接抢走。抢不到才去排队。
对比:
  • 公平锁:公平,不会有人“饿死”,但性能差(要维护队列)。
  • 非公平锁:性能高,吞吐量大。但可能导致排在后面的人一直抢不到。

Q5: 什么是死锁?如何预防?

死锁的四个必要条件:
  1. 互斥:资源一次只能被一个线程占用。
  2. 请求与保持:占着碗里的,还要抢锅里的。
  3. 不可剥夺:不能去强制抢别人正在用的资源。
  4. 循环等待:A 等 B,B 等 C,C 等 A。
预防方案:
  • 资源有序分配:规定所有线程必须按相同的顺序获取锁。
  • 超时退出:尝试获取锁时设置超时时间。
  • 银行家算法:动态分配资源前预测风险。