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.失败轻量级锁就会膨胀为重量级锁。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)