并发篇
2025-05-16 00:37:37 0 举报
java锁
作者其他创作
大纲/内容
唤醒策略: 公平 or 非公平
否
将线程加入等待队列
偏向锁流程
是
线程调用exit释放锁
通过CAS设置_owner为当前线程
CAS 设置线程id是否成功?
开始
线程阻塞/唤醒
抛出 IllegalMonitorStateException
重置_owner为NULL
Synchronized 锁升级
再次尝试获取锁
获取当前锁的持有者信息
直接尝试释放锁
当前线程是否是锁的持有者?
是否存在竞争?
ReentrantLock请求加锁
按照FIFO顺序检查队列
锁是否空闲? _owner == NULL
抛出异常或返回失败
撤销偏向锁
ReentrantLock
Synchronized Monitor 释放重量级锁的过程
_recursions > 0?
进入阻塞队列_EntryList
成功
线程被唤醒或超时?
检查当前线程是否持有锁
是公平锁吗?
被唤醒后再次尝试获取锁
从_EntryList或_cxq中选择线程唤醒
获取锁成功?
轻量级锁持有
膨胀为重量级锁
线程尝试进入ObjectMonitormonitor enter
释放锁并更新状态
Synchronized Monitor 获取锁 重量级锁的过程
ObjectMonitor 是 HotSpot JVM 中重量级锁的实现核心,其 enter 方法负责处理线程获取锁的逻辑(源码位于 hotspot/src/share/vm/runtime/objectMonitor.cpp)。字段作用_owner持有锁的线程指针,NULL 表示锁未被占用。_recursions锁重入次数(可重入锁的核心)。_EntryList阻塞队列,存储等待获取锁的线程(公平锁模式下按 FIFO 唤醒)。_cxq竞争队列,存储短时间未抢到锁的线程(非公平锁模式下优先唤醒)。_WaitSet等待队列,存储调用 wait() 的线程。_spin_count自旋次数,由 JVM 自适应策略动态调整。1. 设计目标减少内核态切换:通过自旋等待避免立即阻塞线程。支持可重入性:通过 _recursions 实现锁重入。平衡公平性与吞吐量:非公平锁(默认)优先唤醒 _cxq 中的线程,公平锁按 FIFO 唤醒。2. 性能影响优点:在高竞争场景下保证线程安全。缺点:线程阻塞和唤醒依赖操作系统调度,带来 上下文切换 和 内核态切换 的开销。3. 适用场景高并发竞争:当轻量级锁自旋失败时触发。长时间临界区:同步块执行时间较长,自旋不划算。调优参数-XX:+UseSpinning启用自旋(默认开启)。-XX:PreBlockSpin设置自旋次数(默认 10)。-XX:+UseAltFastAccess优化 _cxq 队列的访问模式。锁膨胀(Inflate):轻量级锁升级为重量级锁时创建 ObjectMonitor 对象。内存屏障:CAS 操作隐含内存屏障,保证可见性。
自旋次数可以通过参数设置,默认为10
是否偏向当前线程?
1. 偏向锁阶段触发条件:对象初始化且偏向锁启用(默认开启,jdk15关闭)。核心逻辑:首次进入同步块时,对象头记录线程 ID,后续无需 CAS 直接进入。若其他线程尝试竞争,触发 偏向锁撤销,升级为轻量级锁。2. 轻量级锁阶段触发条件:偏向锁撤销或禁用偏向锁。核心逻辑:线程在栈帧中创建 锁记录(Lock Record),通过 CAS 将对象头替换为锁记录指针。若 CAS 成功,持有轻量级锁。若 CAS 失败,进行自旋(默认 10 次),失败后升级为重量级锁。3. 重量级锁阶段触发条件:自旋失败或竞争激烈。核心逻辑:对象关联到 ObjectMonitor,依赖操作系统 Mutex 实现线程阻塞和唤醒。线程进入阻塞队列(_EntryList),由操作系统调度。
操作系统互斥量 Mutex
通过unpark唤醒线程
_owner是否指向当前线程?
尝试直接获取锁
直接进入同步块
是否有等待线程?
ObjectMonitor::exit 方法是重量级锁释放的核心逻辑,负责释放锁资源并唤醒等待线程。其核心步骤围绕重入锁计数递减、锁释放和线程唤醒机制展开(源码位于 hotspot/src/share/vm/runtime/objectMonitor.cpp)。===1. 锁释放的核心机制可重入性:通过 _recursions 实现递归锁,确保单线程多次加锁的安全释放。线程唤醒策略:非公平模式:优先唤醒最近竞争的线程(_cxq),提高吞吐量。公平模式:按 FIFO 顺序唤醒(_EntryList),减少线程饥饿。轻量级唤醒:通过 unpark 唤醒线程而非暴力竞争,减少上下文切换。2. 性能影响优点:基于队列的唤醒机制避免线程“惊群效应”。缺点:频繁的锁竞争仍会导致大量线程阻塞/唤醒操作。3. 适用场景高竞争临界区:需要严格保证线程安全的场景。长时间同步块:不适用轻量级锁的场景。
自旋是否成功?
轻量级锁流程
结束
synchronized
对象初始化:无锁状态
是否启用偏向锁? -XX:+UseBiasedLocking
尝试自旋等待
是否首次进入同步块?
按照FIFO顺序获取锁
自旋尝试
0 条评论
下一页