synchronized锁的底层实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27464169/article/details/89532752

想快速了解通过面试直接看总结部分。

对象内存简图对象内存简图
  1. 对象头:存对象的hashcode,锁信息等。类型指针指向对象类元数据,JVM通过指针确定对象属于哪个类的实例信息。
  2. 实例变量:存放类属性数据信息(包括父类属性)
  3. 填充数据:不是必须存在,为了字节对齐(因为虚拟机要求对象起始地址必须是8字节整数倍)
Monitor对象

每个对象都存在一个monitor,monitor可以和对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个monitor被某个线程持有后,便处于锁定状态。
当在对象上加锁时,数据是记录在对象头中。当执行同步方法或同步代码块时,会在对象头中
记录锁标记,锁标记指向的是monitor对象的起始地址。

ObjectMonitor对象

在Java虚拟机中,monitor是由ObjectMonitor实现的。
ObjectMonitor中有两个队列,_WaitSet 和_EntryList以及_Owner标记。

  • _WaitSet :管理等待队列(wait)线程
  • _EntryList:管理锁池阻塞线程
  • _Owner:记录当前执行线程
原理

Java虚拟机中的同步(synchronized)基于进入和退出Monitor对象(也称为管程或监视器锁)实现。同步方法并不是由monitor enter 和monitor exit指令实现同步的,而是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED标志来隐式实现的。

线程状态图

线程状态图当多线程访问同一个同步代码时,首先会进入锁池队列,当线程获取锁标记以后,由monitor中的owner记录当前执行线程,并在monitor计数器执行递增计算(+1)代表锁定,其他线程在锁池队列继续阻塞。如果执行线程调用wait方法,则monitor计数器执行赋值0计算,并将owner赋值为null,代表放弃锁,执行线程进入waitset中阻塞。若执行线程调用notify/notifyAll方法,waitset线程被唤醒,首先进入就绪状态,然后在进入entrylist中阻塞,等待获取锁标记。若执行线程的同步代码执行结束,同样会释放锁标记,monitor中的owner标记赋值为null,且计数器赋值0计算。

总结

锁底层原理基于Monitor对象实现的,monitor对象能够记录锁池队列,等待队列,和当前执行线程,首先当多线程访问同一个同步代码时,先进入锁池队列进行等待,当线程获取锁标记时,会将monitor对象中的计数器递增1,并对owner进行赋值,代表获取锁,执行完同步代码后会释放锁标记,对monitor计数器赋值0,并对owner进行赋值null,然后随机从锁池队列中选择一个线程重新获取锁标记继续执行。如果当前执行线程调用wait代表放弃锁,则进入waitset等待队列等待被唤醒,唤醒以后先进入就绪状态,然后继续进入锁池队列等待获取锁。

记忆关键词

monitor,锁池队列,等待队列,owner当前执行线程,计数器

创作不易,写个博客不容易,希望路过的各位同胞点个赞,或者评论、关注下!你的支持是我写博客的最大动力!点个赞就行!
如果你想接点程序相关的小活(范围:400元-2000元,土豪可绕行),可以加上我的QQ号(75975175),我这边有机会向您免费提供私活资源,供您参考!

猜你喜欢

转载自blog.csdn.net/qq_27464169/article/details/89532752