Java锁的实现

举报
上善若水. 发表于 2022/09/11 19:44:24 2022/09/11
【摘要】 Java锁的实现在Java SE 1.6中,锁一共有4中状态,级别从低到高依次是:无锁、偏向锁、轻量级锁和重量级锁。 轻量级锁轻量级锁是JDK 1.6之中加入的新型锁机制,它名字中的“轻量级”是相对于使用操作系统互斥量来实现的传统锁而言的,因此传统锁的机制就称为重量级锁。首先需要强调一点的是,轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统...

Java锁的实现

Java SE 1.6中,锁一共有4中状态,级别从低到高依次是:无锁、偏向锁、轻量级锁和重量级锁。

 

轻量级锁

轻量级锁是JDK 1.6之中加入的新型锁机制,它名字中的轻量级是相对于使用操作系统互斥量来实现的传统锁而言的,因此传统锁的机制就称为重量级锁。首先需要强调一点的是,轻量级锁并不是用来代替重量级锁的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。要理解轻量级锁,必须先介绍虚拟机的对象内存布局中的对象头。

 

Java对象头

 

如果对象是数组类型,则虚拟机用3个字宽存储对象头,如果是非数组类型,则用2字宽存储对象头。在32位虚拟机中,1字宽等于4字节,即32bit。在64位虚拟机中,一字宽等于8字节,即64bit

Java对象头里的Mark Word里默认存储对象的HashCode、分代年龄和锁标记位。32JVMMark Word的默认存储结构如下

 

在运行期间,Mark Word里存储的数据会随着锁标志位和偏向锁标志位的变化而变化。Mark Word可能变化为存储以下4种数据:

64位虚拟机下,Mark Word64bit大小的,其存储结构如下:

轻量级锁的加锁过程

在代码进入同步快的时候,如果此同步对象没有被锁定,(锁标志位为“01”状态),虚拟机首先将在当前线程的栈桢中建立一个锁记录(Lock Record)的空间,用于存储锁对象目前的Mark Word的拷贝。

然后,虚拟将使用CAS操作尝试将对象的MarkWord更新为指向LockWord的指针,如果这个更新操作成功了,那么这个线程就拥有了该对象的锁,并且对象Mark Word的锁标志位将转换为“00”,即表示此对象处于轻量级锁定状态

如果这个更新操作失败了,虚拟机首先会检查对象的Mark Word是否指向当前线程的栈桢(栈桢中的Lock Word),如果是说明当前线程已经拥有了这个对象的锁,那就可以直接进入同步块执行了。否则说明这个锁对象已经被其他线程占用了。如果有两条或两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁,锁标志的状态值变为“10”,此时Mark Word中存储的就是指向重量级锁(互斥量)的指针,后面等待锁的线程也就要进入阻塞状态。

轻量级锁的解锁过程

如果对象Mark Word仍然指向当前线程的锁记录(Lock Record),就用CAS操作把对象的Mark Word用当前线程的LockRecord(加锁之前Mark Word的拷贝)进行替换,如果替换成功,整个同步过程就完成了。如果替换失败,说明有其他线程尝试获取该锁,锁就会膨胀为重量级锁

一旦锁升级为重量级锁,就不再恢复到轻量级锁状态。在重量级锁状态下,其他线程试图获取锁时,都会被阻塞,当持有锁的线程释放锁后会唤醒这些线程,被唤醒的线程就会进行新一轮的锁竞争。

 

轻量级锁能提升程序同步性能的依据是“对于绝大部分的锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。如果没有竞争,轻量级锁使用CAS操作避免了使用互斥量的开销,但如果存在锁竞争,除了互斥量的开销,还额外发生了CAS操作,因此在有竞争的情况下,轻量级锁会比传统的重量级锁更慢。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。