Java Lock
锁分类
公平锁/非公平锁
公平锁 入锁前如果阻塞会自动排队到链表最后面;
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
非公平锁 谁先抢到,谁先执行;优势为吞吐量较公平锁大,Synchronized为公平锁;
可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
ReentrantLock 和 Synchronized 是可重入锁
Code View
synchronized void setA() throws Exception{ Thread.sleep(1000); setB(); } synchronized void setB() throws Exception{ Thread.sleep(1000); }
独享锁/共享锁(排它锁)
独享锁是指该锁一次只能被一个线程所持有。
ReentrantLock & Synchronized & ReentrantReadWriteLock writeLock().lock()
共享锁与独占锁相反,可被多个线程持有。
ReentrantReadWriteLock readLock().lock()
`
互斥锁 / 读写锁
互斥锁:与独享锁同义,一次仅限一个线程(如
ReentrantLock
)。读写锁:读共享、写排它(如
ReentrantReadWriteLock
)。
乐观锁 / 悲观锁
悲观锁:默认加锁后再做操作,典型如
Synchronized
、ReentrantLock
。乐观锁:无锁操作前先检查冲突,常见于
CAS
。
分段锁
典型示例
ConcurrentHashMap
(JDK 1.7 以前),将数据分段,锁粒度更细,减少锁冲突。
偏向锁/轻量级锁/重量级锁

在 HotSpot JVM 中,一个对象的内存布局通常可分为 3 部分:
1. 对象结构
对象头(Object Header)
Mark Word
64 位(在 64 位 JVM 下)。
存储对象自身的状态信息(HashCode、GC 分代年龄、锁标记位、偏向锁线程 ID 等)。
类型指针(Klass Pointer)
指向对象所属的类元数据(Klass 结构)。
由于开启了压缩指针(Compressed Oops),常用 32 位存储,然后在访问时进行解压。
实例数据:对象实际字段(含父类继承的字段)。
对齐填充:满足 8 字节对齐的要求。
2. Mark Word 典型布局
以下是一种常见的 64 位 Mark Word 分布(无锁、已计算 HashCode 场景)示例,实际布局可能因 JVM 版本/配置略有不同:
25 bit
存储对象的 25 位 HashCode
4 bit
对象的分代年龄(GC Age)
1 bit
偏向锁标志(Biased Lock)
2 bit
锁标记位(Lock Bits)
32 bit
其他(如空闲或备用字段)
Lock Bits(锁标记位) 一般占用 2 bit。
若偏向锁启用,则还需要额外 1 bit 用来区分“是否偏向”。
根据锁状态的不同(无锁、偏向锁、轻量级锁、重量级锁),Mark Word
中各段的具体含义会动态变化。尤其在“偏向锁”场景下,Mark Word
会记录 线程 ID、epoch 等信息,而不再是简单的 HashCode。
3. 锁标记(Lock Bits)作用
HotSpot 会在 Mark Word
的最低 2 位(有时加上倒数第 3 位的偏向标记),来表示对象当前的锁定状态。常见取值如下表所示(不同版本略有差异,但概念相同):
Lock Bits
Biased Flag
对象锁状态
说明
01
1
偏向锁 (Biased)
无竞争场景,Mark Word 存储线程 ID
00
?
轻量级锁 (Lightweight)
通过 CAS + 自旋获取锁,Mark Word 存储指向锁记录指针
10
?
重量级锁 (Heavyweight)
互斥量 (Monitor) 同步,线程阻塞/唤醒
01
0
无锁 (Unlocked)
初始状态或已计算过 HashCode
11
-
GC 标记 (Marked)
可能是 CMS/G1 阶段做标记等(或其他特殊用途)
具体二进制值对应关系,需结合偏向标志位 (
Biased Flag
) 一起解读。当偏向锁被撤销后,会置为轻量级锁或直接升级到重量级锁。
“
11
” 状态通常在垃圾回收标记、移动对象等场景使用。
4. 总结
整个synchronized锁流程如下:
检测Mark Word里面是不是当前线程的ID,如果是,表示当前线程处于偏向锁
如果不是,则使用CAS将当前线程的ID替换Mard Word,如果成功则表示当前线程获得偏向锁,置偏向标志位1
如果失败,则说明发生竞争,撤销偏向锁,进而升级为轻量级锁。
当前线程使用CAS将对象头的Mark Word替换为锁记录指针,如果成功,当前线程获得锁
如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
如果自旋成功则依然处于轻量级状态。
如果自旋失败,则升级为重量级锁。
自旋锁
【JDK1.4.2~JDK1.6】之间
-XX:+UseSpinning
开启自旋锁【JDK1.7】后,去掉此参数,由jvm控制;
锁消除 锁粗化
类锁 对象锁
无锁
Last updated
Was this helpful?