synchronized锁升级

在 Java SE 1.6中, 一共有 4 种状 级别 低到高依次是: 、偏向 级锁 状 态和重量 级锁 几个状 会随着 争情况逐 可以升 但不能降 ,意味着偏
级锁 后不能降 成偏向

1、偏向锁

大多数情况下, 不存在多 线 争,而且 是由同一线 程多次 得, 让线 的代价更低而引入了偏向 当一个 线访问同步并获取锁时,会在栈帧中的锁记录里存储锁偏向的线ID ,以后 该线 程在 入和退出 同步块时 不需要 CAS 操作来加 和解 ,只需 简单 测试 一下 Mark Word 里是否 存储 着指向当前 线 程的偏向 。如果 测试 成功,表示 线 程已 经获 得了 。如果 测试 需 要再测试 一下 Mark Word 中偏向 标识 是否 置成 1 (表示当前是偏向 ):如果没有 置, 则 使用CAS ;如果 置了, 则尝试 使用 CAS 的偏向 指向当前 线 程。

2、轻量级锁

(1)轻量级锁加锁
线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失
败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。
(2)轻量级锁解锁
轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁

synchronized锁升级_第1张图片

 从图中可以看出,所标志位是00代表轻量级锁,轻量级锁又称自旋锁、无锁(存在歧义尽量不要用此称);标志位是10代表重量级锁;标志位是11代表GC回收;标志位是001代表无锁状态,101代表是偏向锁

锁升级的过程

synchronized锁升级_第2张图片

偏向锁直接调用wait()方法-->重量级锁

匿名偏向--->偏向锁:在synchronized()-->synchronized(o)

偏向锁自旋锁都是用户空间完成;重量级锁是需要向内核申请

当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,从无锁状态升级为偏向锁---->出现竞争,另一个进程争抢资源,就会撤销原来的偏向锁,两个进程开始竞争把对象头中的Mark Word替换为各自的LR指针,一个成功则另一个自旋等待--->当有线程超过10次自旋,-XX:PreBlockSpin,或者自旋线程数超过CPU核数的一半时,锁就会膨胀成重量级锁。在1.6之后,加入自适应自旋Adapative Self Spinning , 由JVM自己控制何时膨胀为重量级锁

为什么有轻量级锁还要有重量级锁?

自旋是消耗CPU资源的,如果锁的时间长,或者自旋线程多,CPU会被大量消耗,重量级锁会把自旋的那些进程,放到WaitSet等待队列,不需要消耗CPU,等待调用

偏向锁是否一定比自旋锁效率高?不一定

不一定,在明确知道会有多线程竞争的情况下,偏向锁肯定会涉及锁撤销,这时候直接使用自旋锁效率更高。所以在JVM启动过程,会有很多线程竞争(明确),所以默认情况启动时不打开偏向锁,过一段儿时间再打开-XX:BiasedLockingstartupDelay=o (一段时间应该是4s)【偏向锁未启动】

 

你可能感兴趣的:(java,java,开发语言)