介绍一下你知道的锁

一、核心概念与分类(基础必问)

从不同维度对锁进行分类。

1. 乐观锁 vs 悲观锁(思想层面)

  • 悲观锁 :认为并发冲突一定会发生 ,因此在操作数据前必须先加锁。典型代表是 synchronized 关键字和 ReentrantLock
    • 类比:假设所有人都会修改数据,所以每次进屋(操作数据)都先锁门。
  • 乐观锁 :认为并发冲突不常发生 ,因此先直接操作数据,在提交更新时再判断是否有冲突。通常通过版本号CAS机制 实现。
    • 典型实现 :数据库的 version 字段,Java中的 AtomicInteger(基于CAS)。
    • 类比:假设大家很少冲突,所以先干事,提交前看一眼有没有人动过(检查版本号)。

2. 公平锁 vs 非公平锁(调度策略)

  • 公平锁 :多个线程按照申请锁的顺序 来获取锁,先到先得。ReentrantLock(true)
    • 优点:不会"饿死"。
    • 缺点:吞吐量较低,需要维护一个队列。
  • 非公平锁 :允许"插队",线程尝试获取锁时,如果锁刚好可用,则直接获取,不管队列里是否有等待者。synchronizedReentrantLock()(默认)。
    • 优点:吞吐量高,减少线程切换开销。
    • 缺点:可能导致某些线程长时间"饿死"。

3. 可重入锁 vs 非可重入锁(能否重复进入)

  • 可重入锁(递归锁) :同一个线程在外层方法获取锁后,在进入内层方法时会自动获取该锁(锁的计数器+1)。synchronizedReentrantLock 都是可重入的。
    • 优点:避免死锁,方便递归和嵌套调用。
    • 示例synchronized 方法A调用另一个 synchronized 方法B。
  • 非可重入锁:与之相反,自己锁了自己就不能再进了。

4. 独享锁(排他锁) vs 共享锁(读写锁)

  • 独享锁 :一次只能被一个线程持有。synchronizedReentrantLock 是独享锁。
  • 共享锁 :允许多个线程同时持有。典型代表是 ReentrantReadWriteLock.ReadLock
    • 读写锁ReentrantReadWriteLockReadLock(共享)和 WriteLock(独享)的组合,遵循 "读读共享、读写互斥、写写互斥" 的原则,能极大提升读多写少场景的性能。
    • 升级 :JDK 8 引入了性能更好的 StampedLock,提供了乐观读、读写锁转换等更灵活的功能。

5. 自旋锁 vs 互斥锁

自旋锁: 当没拿到锁时, 不会释放CPU, 而是一直处于活跃状态(while循环), 一直循环判断锁是否被释放. 循环时间一长十分消耗CPU资源.

互斥锁: 没拿到锁就释放CPU, 进入阻塞等待状态, 直到被唤醒.

二、关键锁的实现与原理(进阶高频)

1. synchronized 关键字

  • 用法:修饰实例方法、静态方法、代码块。
  • 原理:JVM 层面实现。
  • 锁升级过程(重点!) :为了在性能和开销间取得平衡,JDK 1.6 后引入了"偏向锁 -> 轻量级锁 -> 重量级锁"的升级过程,锁只能升级不能降级。
    • 无锁:新对象。
    • 偏向锁:假设只有一个线程访问,会在对象头Mark Word记录线程ID。后续该线程进入/退出同步块只需要检查ID,无需CAS。
    • 轻量级锁:当有第二个线程竞争时,升级为轻量级锁。通过CAS自旋(适应性自旋)尝试获取锁,避免直接进入内核态阻塞。
    • 重量级锁 :自旋失败或竞争激烈时,升级为重量级锁(操作系统层面的互斥量 Mutex),线程进入阻塞队列,性能消耗最大。
  • 面试点synchronizedReentrantLock 的区别。
    先尝试偏向锁,降低无竞争的开销;出现竞争时,升级为轻量级锁,通过自旋避免阻塞;自旋失败(竞争加剧),最终升级为重量级锁,让线程阻塞。当 synchronized 升级为重量级锁时,它需要通过操作系统的互斥锁(Mutex Lock)来实现线程的阻塞和唤醒
    2. ReentrantLock(AQS 的代表)
  • 核心 :基于 AbstractQueuedSynchronizer(AQS) 实现。AQS 内部维护了一个 volatile int state(同步状态)和一个 CLH 变体的FIFO双向队列(阻塞线程队列)。
  • 原理
    • 加锁 :通过 lock() -> acquire() -> tryAcquire() 尝试获取锁(修改 state 从0到1),成功则独占;失败则通过 addWaiter() 将线程封装为 Node 加入队列尾部,并通过 acquireQueued() 进行自旋或阻塞。
    • 解锁unlock() -> release() -> tryRelease()state 减为0,并 unparkSuccessor() 唤醒队列中的下一个线程。
  • 优势 :相比 synchronized,提供了更多功能:可中断 (lockInterruptibly())、可定时 (tryLock(timeout))、可设置公平/非公平支持多个条件变量 (Condition)。

3. CAS(Compare And Swap)与原子类

  • CAS:乐观锁的核心实现,是一条CPU原子指令。操作包含三个值:内存位置 V、预期原值 A、新值 B。仅当 V == A 时,才将 V 更新为 B。
  • 原子类java.util.concurrent.atomic 包下的类(如 AtomicInteger)使用 CAS 实现无锁线程安全操作。
  • 缺点
    • ABA问题 :值从A变成B又变回A,CAS会认为没变。解决方案是使用 AtomicStampedReference (带版本戳)。
    • 循环时间长开销大:自旋CAS如果长时间不成功,会消耗CPU。
    • 只能保证一个共享变量的原子操作 。可以用 AtomicReference 封装多个变量。
相关推荐
藦卡机器人5 小时前
中国工业机器人发展现状
大数据·人工智能·机器人
Simon_lca5 小时前
突破合规瓶颈:ZDHC Supplier to Zero(工厂零排放 - 进阶型)体系全攻略
大数据·网络·人工智能·分类·数据挖掘·数据分析·零售
黄焖鸡能干四碗7 小时前
网络安全建设实施方案(Word文件参考下载)
大数据·网络·人工智能·安全·web安全·制造
云境筑桃源哇8 小时前
马踏春风 为爱启航 | 瑞派宠物医院(南部新城旗舰店)盛大开业!打造宠物医疗新标杆!
大数据·宠物
xixixi777779 小时前
2026 年 03 月 20 日 AI+通信+安全行业日报(来更新啦)
大数据·人工智能·安全·ai·大模型·通信
F36_9_9 小时前
大数据治理平台选型避坑:2026 年 8 大主流系统实测
大数据·数据治理
成长之路5149 小时前
【实证分析】A股上市公司企业劳动力需求数据集(2000-2023年)
大数据
奔跑的呱呱牛9 小时前
GeoJSON 在大数据场景下为什么不够用?替代方案分析
java·大数据·servlet·gis·geojson
Lab_AI9 小时前
电池材料行业数据管理新突破:AI4S驱动的科学数据平台正在重塑电池材料开发范式
大数据·人工智能·ai4s·电池材料开发·电池材料研发·电池材料创新·ai材料研发
FindAI发现力量9 小时前
智能工牌:线下销售场景的数字化赋能解决方案
大数据·人工智能·销售管理·ai销售·ai销冠·销售智能体