Synchronized 到底是如何执行加锁?

引言

虽然我们平常在解决多线程并发问题的时候都使用过 Java 中提供的 synchronized 关键字。但是当被提问到底层是如何实现时,却不知道从何谈起,这篇文章带你了解一下 synchronized 的底层实现。

Java对象头

要想了解 synchronized 是怎么实现的要先了解一下 Java对象头的内容。
在这里插入图片描述

  • Klass Word: 每个对象都有自己的类型,比如 Student、Teacher 等等,这些类型都是由后 32 位(4个字节)的 Klass Word所表示的。它是一个指针,指向了对象所从属的 class。

  • Mark Word结构:

    • hashcode:就是哈希码
    • age:表示在垃圾回收中的分代年龄
    • biased_lock:表示的是偏向锁的状态
    • 最后两位表示加锁状态
      在这里插入图片描述
      当加的锁是不同的锁时,Mark Word 的结构也会各有不同,主要有上述的一些状态,State 有标注。具体下次介绍。

Monitor

说完对象头,我们在了解一下 Monitor 的结构。
每一个对象都可以关联一个 Monitor对象,如果使用 synchronized 给对象加锁时(重量级锁),该对象头的 Mark Word就是被设置为指向Monitor的对象指针。

Monitor 的结构如下:
在这里插入图片描述主要分为三个区域:

  • Owner:指向成功获取锁的线程
  • EntryList:阻塞队列,表示没有竞争到锁的线程都会进入到阻塞队列中
  • WaitSet:获得锁后,调用了 wait 方法的线程都会进入到 WaitSet当中。

大致流程

  1. 当一个线程进入到了 synchronized 会进行加锁(假设重量级锁),这时这个对象头的Mark Word 会指向一个Monitor对象。这时候对象头的结构为:在这里插入图片描述
  2. 由于这时候没有别的线程过来竞争,所以 Monitor对象的 Owner会指向获取锁的该线程。
  3. 然后当这个线程还没有释放锁的时候,有别的线程进入到 synchronized 进行加锁获取对象时,发现这个对象头已经指向了有Monitor对象,并且Owner也指向别的一个线程,这时候这个线程就会进入到EntryList中进行阻塞。
  4. 当获取锁的线程执行完成之后,会将Owner置为 null,这时EntryList中的线程会进入锁竞争(非公平的),抢到锁的线程会进行下一步,如果没有抢到锁还是会呆在EntryList中进行阻塞,等待下一次竞争锁。

注意:

  • synchronized 必须进入的是同一个 Monitor对象才有上述的流程
  • 不加 synchronized 的对象不会关联 Monitor对象,也不会有上面的这些规则。

下期详细介绍 synchronized的优化

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值