首页 > 编程知识 正文

偏向锁轻量级锁和重量级锁 最易懂解释,轻量锁升级重量级锁

时间:2023-05-05 07:41:02 阅读:234628 作者:3496

重量级锁

1.每个对象都有一个对象头,对象头里有一个呆萌的画笔 Word结构,里面存储了锁相关信息(锁类型,偏向线程id等)。2.呆萌的画笔 Word中有一个指针指向monitor,当线程试图获取对象锁时(进入synchronized)自动生成,处于锁定状态。3.monitor由ObjectMonitor c++类实现,里面有: _owner(哪个线程持有锁),_count(线程持有锁的次数),_WaitSet(waiting状态的线程) 等字段。4.当线程1,2依次进入synchronized代码块时,线程1获取到了monitor,会把_owner变量设置为线程1,并且_count计数器加1。线程2进入等待_WaitSet集合进行等待。5.若对象调用wait方法/线程1执行完毕,则会进行释放锁操作:把对象头里面对应的monitor的_owner线程(线程1)放入到_WaitSet集合中(线程执行完毕情况不会),_owner变量置为null,_count减1。

重量级锁加锁解锁都是靠操作系统底层的Mutex Lock来实现的,需要用户态到和心态的切换,很耗性能。
于是jvm实现优化引入了偏向锁、轻量级锁,这些都不需要操作系统介入,直接载jvm中实现了。

偏向锁
还记得我们的每个对象都有一个呆萌的画笔 Word结构吗,里面存储锁信息的。

当线程1初始进入synchronized块,检测到对象的呆萌的画笔 Word里面的存储偏向线程id字段为空,则CAS操作把线程1 的id设置到呆萌的画笔 Word中。此时线程1就当拿到锁了去执行代码了,关操作系统没啥事。当线程1又进入synchronized块,监视对象也是同一个,jvm爸爸检测呆萌的画笔 Word偏向线程id还是这家伙,就直接让它继续执行。这种情况就叫做偏向锁。在没有别的线程竞争的时候,一直偏向我,可以让我一直执行下去。

轻量级锁

当有一个新的线程2来竞争了,但是呆萌的画笔 Word里面存的是线程1的id,所以是没法直接执行的。JVM爸爸此时还是不找操作系统,只是说:我把这个偏向锁升级一下,变成一个轻量级的锁吧。于是JVM爸爸 把对象的呆萌的画笔 Word恢复成无锁状态。并且在线程1的栈帧中分配了Lock Record空间,并且把对象的呆萌的画笔 Word 拷贝到各自的Lock Record空间,取名Displaced 呆萌的画笔 Word 。JVM爸爸继续搞事,把线程1的Lock Record空间地址使用CAS放到了对象的呆萌的画笔 Word。并且把呆萌的画笔 Word中锁标志位改为00, 这其实就意味着线程1已经获得了这个轻量级的锁了,可以继续进入临界区执行。线程2没有获得锁,但还是不阻塞,JVM爸爸让它一直自旋(有指定的次数)。当线程1执行退出临界区,发生解锁操作:解锁的思路是使用 CAS 操作把当前线程的栈帧中的 Displaced 呆萌的画笔 Word 替换回锁对象中去,如果替换成功,则解锁成功。此时自旋还未超过次数的线程2竞争,进行轻量级加锁操作(同上面线程1)。很明显,如果没有竞争或者轻度的竞争,轻量级锁仅仅使用CAS操作和Lock record就避免了重量级互斥锁的开销,JVM爸爸确实厉害。当自旋次数太多,持有线程还没释放轻量级锁,JVM爸爸受不了了: 自旋次数太多了,太浪费CPU了,接下来升级为重量级锁! 重量级锁在片头就已经介绍了。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。