2.偏向锁,轻量锁,重量锁

2.偏向锁,轻量锁,重量锁,第1张

1.偏向锁,我们在保证线程安全的的情况下,实际情况下,不一定有互斥,如果锁对象没有其他竞争资源,则 *** 作系统默认会为偏向锁,锁总是同一个线程持有,很少发生竞争”,也就是说锁总是被第一个占用他的线程拥有,偏向锁不会调用os 函数,main函数启动式,但是会存在延时加载,此段时间为轻量锁

2.轻量锁,偏向锁升级 JVM 启动式默认是偏向锁,---两个线程交替执行,无竞争

 轻量锁与偏向锁不同的是:

轻量级锁每次退出同步块都需要释放锁,而偏向锁是在竞争发生时才释放锁

每次进入退出同步块都需要CAS更新对象头

争夺轻量级锁失败时,自旋尝试抢占锁

 可以看到轻量锁适合在竞争情况下使用,其自旋锁可以保证响应速度快,但自旋 *** 作会占用CPU,所以一些计算时间长的 *** 作不适合使用轻量级锁。

3.synchronized 是重量锁(mutex--互斥),借助OS函数实现的锁,当竞争线程尝试占用轻量级锁失败多次之后,轻量级锁就会膨胀为重量级锁,重量级线程指针指向竞争线程,竞争线程也会阻塞,等待轻量级线程释放锁后唤醒他。

一句话概括:没有资源竞争(偏向锁),有资源竞争(轻量锁),资源多次竞争失败,轻量锁升级(重量)

证明偏向锁

Linux 打印线程id 使用c打印线程id,在linux中打印只会打印一次;而重量锁则会交替打印

JVM为了性能,对内置锁做了优化,比如内置锁的分配和膨胀

内置锁只能沿着偏向锁,轻量级锁,重量级锁的顺序逐渐升级,不能降级。

为了减少线程切换(线程挂起和恢复线程都会引起CPU用户态和内核态的切换)的开销,所以产生了自旋锁。

当线程竞争锁失败后,会通过自旋(如空等待)一会,自选的过程中也会竞争锁。如果这个过程没有竞争到锁,那么就会阻塞自己。

注:单核处理器的情况下,是伪并行,只可能存在一个线程执行,所以自旋锁是无意义的。

-XX:-UseSpinning参数关闭自旋锁优化;-XX:PreBlockSpin参数修改默认的自旋次数。

即自旋的时间由前一次这个锁的自旋时间决定:同一个锁对象上,如果上次自旋获得过锁,那么虚拟机允许它自旋等待持续更长的时间;如果很少成功获取锁,那么就会减少自旋时间。

偏向锁:无实际竞争,只有第一个申请锁的线程会使用锁

1.偏向锁会偏向第一个获得它的线程。

2.当线程获取锁的时候,先检查Mark Word是否是可偏向锁的状态。是则检查Mark Word中存储的线程是否为当前线程Id,是则获取成功

3.如果不是,则通过CAS去将其修改成本线程Id,修改成功则一切顺利,失败就会在拥有该锁的线程达到安全点(指当前时间没有字节码正在执行)之后,挂起该线程,升级为轻量级锁。

1.当有线程膨胀为轻量级锁之后,其他线程来竞争锁,虚拟机会在当前线程的栈帧中创建一个锁记录的空间,存储锁对象的Mark Word的拷贝。并拷贝

2.虚拟机使用CAS *** 作尝试将对象的Mark word更新为指向锁记录的指针,成功,那么该线程就拥有了该对象的锁

3.失败轻量级锁就会膨胀为重量级锁。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/5900261.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-07
下一篇 2023-03-07

发表评论

登录后才能评论

评论列表(0条)

保存