Synchronized底层以及锁升级机制

提到java锁机制,就得先弄清java对象结构

对象头的三个字段:

  1. Mark Word

用于存储自身运行时的数据,例如GC标志位、哈希码、锁状态

  1. Class Pointer

存放方法区Class对象地址,通过这个指针确定这个对象是哪个类的实例

  1. Array Length

非必须,记录数组长度(如果是数组的话)

在32位JVM虚拟机中,Mark Word和Class Pointer这两部分都是32位的;在64位JVM虚拟机中,Mark Word和Class Pointer这两部分都是64位的。而我们需要重点理解的时mark word , 因为它跟synchronized的底层原理有关。

Mark Word

Synchronized

底层原理是生成monitorenter 和 monitorexit指令来进行线程同步,依赖于操作系统的Mutex Lock来实现的,所以每当挂起或唤醒一个线程都要切换到操作系统的内核态,性能消耗大,效率低。从JAVA6开始就引入了锁升级的概念。

对象锁的四种状态

无锁:没有对资源进行操作系统级别的锁定(Mutex Lock)

偏向锁:我们想在用户态就把这个资源的事务完成,无需切换到内核态。最好让对象能够认识这个线程,只要是这个线程来尝试获取,对象就直接把锁交出去。在对象头中的倒数第三bit 有个是否是偏向锁的标志位,如果是1,那么就去读Mark Word前23个bit,获取线程ID,通过线程ID来确认想要获得对象锁的线程是不是“偏向”的线程(有点像MVCC去获取up_limit_id 对比 transaction id的感觉了)

假如对象发现目前不止有一个线程,而有多个线程在竞争锁,那么偏向锁会升级轻量级锁

轻量级锁:升级到轻量级锁的时候,Mark Word的前30bit都用来表示指向栈中锁记录的指针。当一个线程过来要获得某个对象的锁的时候,假如看到锁标志位是00,那么就知道是轻量级锁,这个时候线程会在自己虚拟机栈开辟一块空间,称为”Lock Record“。

这个Lock Record存放了一个Mark Word的副本,以及Owner指针。然后线程就开始通过CAS去获取锁(自旋,默认10次吧好像是),一旦获得,将会复制这个对象的Mark Word到虚拟机栈的Lock Record中,并将之前的Owner指针指向该对象锁。然后Mark Word前30bit的指针将会指向这个Lock Record。这样就完成了线程和对象锁的绑定。

如果这时候有其他线程来了,想获取这个对象的锁。那他们就自旋等待。当然这个自选等待有区别与操作系统的阻塞,它是在用户态进行的,效率相比起来会高一些。一旦自选等待的线程数超过一个,那么轻量级锁就会升级为重量级锁。

重量级锁

那就是大的来了。也就是最严格的同步控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值